We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Praw incorrectly uses the "after" parameter to paginate Mode Note API Queries.
### Describe the Bug

The Reddit API does not support using the parameter "after" on queries for /api/mod/notes

The default listing generator uses the "after" parameter to paginate results.

Generator.py
```
    if self._listing.after and self._listing.after != self.params.get("after"):
                self.params["after"] = self._listing.after
            else:
                self._exhausted = True
```

The "after" parameter is set as part of the listing class.

```
    class ModNoteListing(Listing):
        """Special Listing for handling :class:`.ModNote` lists."""
    
        CHILD_ATTRIBUTE = "mod_notes"
    
        @property
        def after(self) -> Optional[Any]:
            """Return the next attribute or None."""
            if not getattr(self, "has_next_page", True):
                return None
            return getattr(self, "end_cursor", None)
```

The result is that the reddit API will ignore the 'after' parameter and return an identical result to the first query. When PRAW receives a second response with an identical  'end_cursor' parameter, it will end the query. This means that the maximum number of mod notes pulled by PRAW is 100.

### Desired Result

PRAW should record the  'end_cursor' parameter from responses to the Mod Notes API and transmit them as "before" in the next query. This will properly collect the next page of results from the API.

I do not have the python knowledge to provide a best practice fix. Below is my hack that correctly provides all user notes.

listing.py
```
class ModNoteListing(Listing):
    """Special Listing for handling :class:`.ModNote` lists."""

    CHILD_ATTRIBUTE = "mod_notes"

    @property
    def before(self) -> Optional[Any]:
        """Return the next attribute or None."""
        if not getattr(self, "has_next_page", True):
            return None
        return getattr(self, "end_cursor", None)
```

generator.py
```
    def _next_batch(self):
        if self._exhausted:
            raise StopIteration()

        self._listing = self._reddit.get(self.url, params=self.params)
        self._listing = self._extract_sublist(self._listing)
        self._list_index = 0

        if not self._listing:
            raise StopIteration()

        if hasattr(self._listing, "after"):
            if self._listing.after and self._listing.after != self.params.get("after"):
                self.params["after"] = self._listing.after
            else:
                self._exhausted = True
        elif hasattr(self._listing, "before"):
            if self._listing.before and self._listing.before != self.params.get("before"):
                self.params["before"] = self._listing.before
            else:
                self._exhausted = True
        else:
            self._exhausted = True
```

### Relevant Logs

```shell
DEBUG:prawcore:Params: {'subreddit': Subreddit(display_name='test'), 'user': 'TestUser', 'limit': 1024, 'raw_json': 1}
DEBUG:prawcore:Response: 200 (5089 bytes)
DEBUG:prawcore:Params: {'subreddit': Subreddit(display_name='test), 'user': 'testUser', 'limit': 1024, 'after': 'MTY2MDIzMTM3MDk5Mw==', 'raw_json': 1}
DEBUG:prawcore:Response: 200 (5089 bytes)
```


### Code to reproduce the bug

```python
for note in reddit.subreddit("test").mod.notes.redditors(userName, limit = None):
```


### My code example does not include the `Reddit()` initialization to prevent credential leakage.

Yes

### This code has previously worked as intended.

No

### Operating System/Environment

Windows 10

### Python Version

Python 3.10

### PRAW Version

Version: 7.6.1

### Prawcore Version

Version: 2.3.0

### Anything else?

The user will need more than 100 mod notes in order to need to paginate requests.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `praw/models/listing/generator.py`
Content:
```
1 """Provide the ListingGenerator class."""
2 from copy import deepcopy
3 from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Union
4 
5 from ..base import PRAWBase
6 from .listing import FlairListing, ModNoteListing
7 
8 if TYPE_CHECKING:  # pragma: no cover
9     import praw
10 
11 
12 class ListingGenerator(PRAWBase, Iterator):
13     """Instances of this class generate :class:`.RedditBase` instances.
14 
15     .. warning::
16 
17         This class should not be directly utilized. Instead, you will find a number of
18         methods that return instances of the class here_.
19 
20     .. _here: https://praw.readthedocs.io/en/latest/search.html?q=ListingGenerator
21 
22     """
23 
24     def __init__(
25         self,
26         reddit: "praw.Reddit",
27         url: str,
28         limit: int = 100,
29         params: Optional[Dict[str, Union[str, int]]] = None,
30     ):
31         """Initialize a :class:`.ListingGenerator` instance.
32 
33         :param reddit: An instance of :class:`.Reddit`.
34         :param url: A URL returning a Reddit listing.
35         :param limit: The number of content entries to fetch. If ``limit`` is ``None``,
36             then fetch as many entries as possible. Most of Reddit's listings contain a
37             maximum of 1000 items, and are returned 100 at a time. This class will
38             automatically issue all necessary requests (default: ``100``).
39         :param params: A dictionary containing additional query string parameters to
40             send with the request.
41 
42         """
43         super().__init__(reddit, _data=None)
44         self._exhausted = False
45         self._listing = None
46         self._list_index = None
47         self.limit = limit
48         self.params = deepcopy(params) if params else {}
49         self.params["limit"] = limit or 1024
50         self.url = url
51         self.yielded = 0
52 
53     def __iter__(self) -> Iterator[Any]:
54         """Permit :class:`.ListingGenerator` to operate as an iterator."""
55         return self
56 
57     def __next__(self) -> Any:
58         """Permit :class:`.ListingGenerator` to operate as a generator."""
59         if self.limit is not None and self.yielded >= self.limit:
60             raise StopIteration()
61 
62         if self._listing is None or self._list_index >= len(self._listing):
63             self._next_batch()
64 
65         self._list_index += 1
66         self.yielded += 1
67         return self._listing[self._list_index - 1]
68 
69     def _extract_sublist(self, listing):
70         if isinstance(listing, list):
71             return listing[1]  # for submission duplicates
72         elif isinstance(listing, dict):
73             classes = [FlairListing, ModNoteListing]
74 
75             for listing_type in classes:
76                 if listing_type.CHILD_ATTRIBUTE in listing:
77                     return listing_type(self._reddit, listing)
78             else:
79                 raise ValueError(
80                     "The generator returned a dictionary PRAW didn't recognize."
81                     " File a bug report at PRAW."
82                 )
83         return listing
84 
85     def _next_batch(self):
86         if self._exhausted:
87             raise StopIteration()
88 
89         self._listing = self._reddit.get(self.url, params=self.params)
90         self._listing = self._extract_sublist(self._listing)
91         self._list_index = 0
92 
93         if not self._listing:
94             raise StopIteration()
95 
96         if self._listing.after and self._listing.after != self.params.get("after"):
97             self.params["after"] = self._listing.after
98         else:
99             self._exhausted = True
100
```

Path: `praw/models/listing/listing.py`
Content:
```
1 """Provide the Listing class."""
2 from typing import Any, Optional
3 
4 from ..base import PRAWBase
5 
6 
7 class Listing(PRAWBase):
8     """A listing is a collection of :class:`.RedditBase` instances."""
9 
10     CHILD_ATTRIBUTE = "children"
11 
12     def __len__(self) -> int:
13         """Return the number of items in the Listing."""
14         return len(getattr(self, self.CHILD_ATTRIBUTE))
15 
16     def __getitem__(self, index: int) -> Any:
17         """Return the item at position index in the list."""
18         return getattr(self, self.CHILD_ATTRIBUTE)[index]
19 
20     def __setattr__(self, attribute: str, value: Any):
21         """Objectify the ``CHILD_ATTRIBUTE`` attribute."""
22         if attribute == self.CHILD_ATTRIBUTE:
23             value = self._reddit._objector.objectify(value)
24         super().__setattr__(attribute, value)
25 
26 
27 class FlairListing(Listing):
28     """Special Listing for handling flair lists."""
29 
30     CHILD_ATTRIBUTE = "users"
31 
32     @property
33     def after(self) -> Optional[Any]:
34         """Return the next attribute or ``None``."""
35         return getattr(self, "next", None)
36 
37 
38 class ModeratorListing(Listing):
39     """Special Listing for handling moderator lists."""
40 
41     CHILD_ATTRIBUTE = "moderators"
42 
43 
44 class ModNoteListing(Listing):
45     """Special Listing for handling :class:`.ModNote` lists."""
46 
47     CHILD_ATTRIBUTE = "mod_notes"
48 
49     @property
50     def after(self) -> Optional[Any]:
51         """Return the next attribute or None."""
52         if not getattr(self, "has_next_page", True):
53             return None
54         return getattr(self, "end_cursor", None)
55 
56 
57 class ModmailConversationsListing(Listing):
58     """Special Listing for handling :class:`.ModmailConversation` lists."""
59 
60     CHILD_ATTRIBUTE = "conversations"
61 
62     @property
63     def after(self) -> Optional[str]:
64         """Return the next attribute or ``None``."""
65         try:
66             return self.conversations[-1].id
67         except IndexError:
68             return None
69
```
--- 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/praw/models/listing/generator.py b/praw/models/listing/generator.py
--- a/praw/models/listing/generator.py
+++ b/praw/models/listing/generator.py
@@ -93,7 +93,9 @@
         if not self._listing:
             raise StopIteration()
 
-        if self._listing.after and self._listing.after != self.params.get("after"):
-            self.params["after"] = self._listing.after
+        if self._listing.after and self._listing.after != self.params.get(
+            self._listing.AFTER_PARAM
+        ):
+            self.params[self._listing.AFTER_PARAM] = self._listing.after
         else:
             self._exhausted = True
diff --git a/praw/models/listing/listing.py b/praw/models/listing/listing.py
--- a/praw/models/listing/listing.py
+++ b/praw/models/listing/listing.py
@@ -7,6 +7,7 @@
 class Listing(PRAWBase):
     """A listing is a collection of :class:`.RedditBase` instances."""
 
+    AFTER_PARAM = "after"
     CHILD_ATTRIBUTE = "children"
 
     def __len__(self) -> int:
@@ -44,6 +45,7 @@
 class ModNoteListing(Listing):
     """Special Listing for handling :class:`.ModNote` lists."""
 
+    AFTER_PARAM = "before"
     CHILD_ATTRIBUTE = "mod_notes"
 
     @property

{"golden_diff": "diff --git a/praw/models/listing/generator.py b/praw/models/listing/generator.py\n--- a/praw/models/listing/generator.py\n+++ b/praw/models/listing/generator.py\n@@ -93,7 +93,9 @@\n         if not self._listing:\n             raise StopIteration()\n \n-        if self._listing.after and self._listing.after != self.params.get(\"after\"):\n-            self.params[\"after\"] = self._listing.after\n+        if self._listing.after and self._listing.after != self.params.get(\n+            self._listing.AFTER_PARAM\n+        ):\n+            self.params[self._listing.AFTER_PARAM] = self._listing.after\n         else:\n             self._exhausted = True\ndiff --git a/praw/models/listing/listing.py b/praw/models/listing/listing.py\n--- a/praw/models/listing/listing.py\n+++ b/praw/models/listing/listing.py\n@@ -7,6 +7,7 @@\n class Listing(PRAWBase):\n     \"\"\"A listing is a collection of :class:`.RedditBase` instances.\"\"\"\n \n+    AFTER_PARAM = \"after\"\n     CHILD_ATTRIBUTE = \"children\"\n \n     def __len__(self) -> int:\n@@ -44,6 +45,7 @@\n class ModNoteListing(Listing):\n     \"\"\"Special Listing for handling :class:`.ModNote` lists.\"\"\"\n \n+    AFTER_PARAM = \"before\"\n     CHILD_ATTRIBUTE = \"mod_notes\"\n \n     @property\n", "issue": "Praw incorrectly uses the \"after\" parameter to paginate Mode Note API Queries.\n### Describe the Bug\n\nThe Reddit API does not support using the parameter \"after\" on queries for /api/mod/notes\r\n\r\nThe default listing generator uses the \"after\" parameter to paginate results.\r\n\r\nGenerator.py\r\n```\r\n    if self._listing.after and self._listing.after != self.params.get(\"after\"):\r\n                self.params[\"after\"] = self._listing.after\r\n            else:\r\n                self._exhausted = True\r\n```\r\n\r\nThe \"after\" parameter is set as part of the listing class.\r\n\r\n```\r\n    class ModNoteListing(Listing):\r\n        \"\"\"Special Listing for handling :class:`.ModNote` lists.\"\"\"\r\n    \r\n        CHILD_ATTRIBUTE = \"mod_notes\"\r\n    \r\n        @property\r\n        def after(self) -> Optional[Any]:\r\n            \"\"\"Return the next attribute or None.\"\"\"\r\n            if not getattr(self, \"has_next_page\", True):\r\n                return None\r\n            return getattr(self, \"end_cursor\", None)\r\n```\r\n\r\nThe result is that the reddit API will ignore the 'after' parameter and return an identical result to the first query. When PRAW receives a second response with an identical  'end_cursor' parameter, it will end the query. This means that the maximum number of mod notes pulled by PRAW is 100.\n\n### Desired Result\n\nPRAW should record the  'end_cursor' parameter from responses to the Mod Notes API and transmit them as \"before\" in the next query. This will properly collect the next page of results from the API.\r\n\r\nI do not have the python knowledge to provide a best practice fix. Below is my hack that correctly provides all user notes.\r\n\r\nlisting.py\r\n```\r\nclass ModNoteListing(Listing):\r\n    \"\"\"Special Listing for handling :class:`.ModNote` lists.\"\"\"\r\n\r\n    CHILD_ATTRIBUTE = \"mod_notes\"\r\n\r\n    @property\r\n    def before(self) -> Optional[Any]:\r\n        \"\"\"Return the next attribute or None.\"\"\"\r\n        if not getattr(self, \"has_next_page\", True):\r\n            return None\r\n        return getattr(self, \"end_cursor\", None)\r\n```\r\n\r\ngenerator.py\r\n```\r\n    def _next_batch(self):\r\n        if self._exhausted:\r\n            raise StopIteration()\r\n\r\n        self._listing = self._reddit.get(self.url, params=self.params)\r\n        self._listing = self._extract_sublist(self._listing)\r\n        self._list_index = 0\r\n\r\n        if not self._listing:\r\n            raise StopIteration()\r\n\r\n        if hasattr(self._listing, \"after\"):\r\n            if self._listing.after and self._listing.after != self.params.get(\"after\"):\r\n                self.params[\"after\"] = self._listing.after\r\n            else:\r\n                self._exhausted = True\r\n        elif hasattr(self._listing, \"before\"):\r\n            if self._listing.before and self._listing.before != self.params.get(\"before\"):\r\n                self.params[\"before\"] = self._listing.before\r\n            else:\r\n                self._exhausted = True\r\n        else:\r\n            self._exhausted = True\r\n```\n\n### Relevant Logs\n\n```shell\nDEBUG:prawcore:Params: {'subreddit': Subreddit(display_name='test'), 'user': 'TestUser', 'limit': 1024, 'raw_json': 1}\r\nDEBUG:prawcore:Response: 200 (5089 bytes)\r\nDEBUG:prawcore:Params: {'subreddit': Subreddit(display_name='test), 'user': 'testUser', 'limit': 1024, 'after': 'MTY2MDIzMTM3MDk5Mw==', 'raw_json': 1}\r\nDEBUG:prawcore:Response: 200 (5089 bytes)\n```\n\n\n### Code to reproduce the bug\n\n```python\nfor note in reddit.subreddit(\"test\").mod.notes.redditors(userName, limit = None):\n```\n\n\n### My code example does not include the `Reddit()` initialization to prevent credential leakage.\n\nYes\n\n### This code has previously worked as intended.\n\nNo\n\n### Operating System/Environment\n\nWindows 10\n\n### Python Version\n\nPython 3.10\n\n### PRAW Version\n\nVersion: 7.6.1\n\n### Prawcore Version\n\nVersion: 2.3.0\n\n### Anything else?\n\nThe user will need more than 100 mod notes in order to need to paginate requests.\n", "before_files": [{"content": "\"\"\"Provide the ListingGenerator class.\"\"\"\nfrom copy import deepcopy\nfrom typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Union\n\nfrom ..base import PRAWBase\nfrom .listing import FlairListing, ModNoteListing\n\nif TYPE_CHECKING:  # pragma: no cover\n    import praw\n\n\nclass ListingGenerator(PRAWBase, Iterator):\n    \"\"\"Instances of this class generate :class:`.RedditBase` instances.\n\n    .. warning::\n\n        This class should not be directly utilized. Instead, you will find a number of\n        methods that return instances of the class here_.\n\n    .. _here: https://praw.readthedocs.io/en/latest/search.html?q=ListingGenerator\n\n    \"\"\"\n\n    def __init__(\n        self,\n        reddit: \"praw.Reddit\",\n        url: str,\n        limit: int = 100,\n        params: Optional[Dict[str, Union[str, int]]] = None,\n    ):\n        \"\"\"Initialize a :class:`.ListingGenerator` instance.\n\n        :param reddit: An instance of :class:`.Reddit`.\n        :param url: A URL returning a Reddit listing.\n        :param limit: The number of content entries to fetch. If ``limit`` is ``None``,\n            then fetch as many entries as possible. Most of Reddit's listings contain a\n            maximum of 1000 items, and are returned 100 at a time. This class will\n            automatically issue all necessary requests (default: ``100``).\n        :param params: A dictionary containing additional query string parameters to\n            send with the request.\n\n        \"\"\"\n        super().__init__(reddit, _data=None)\n        self._exhausted = False\n        self._listing = None\n        self._list_index = None\n        self.limit = limit\n        self.params = deepcopy(params) if params else {}\n        self.params[\"limit\"] = limit or 1024\n        self.url = url\n        self.yielded = 0\n\n    def __iter__(self) -> Iterator[Any]:\n        \"\"\"Permit :class:`.ListingGenerator` to operate as an iterator.\"\"\"\n        return self\n\n    def __next__(self) -> Any:\n        \"\"\"Permit :class:`.ListingGenerator` to operate as a generator.\"\"\"\n        if self.limit is not None and self.yielded >= self.limit:\n            raise StopIteration()\n\n        if self._listing is None or self._list_index >= len(self._listing):\n            self._next_batch()\n\n        self._list_index += 1\n        self.yielded += 1\n        return self._listing[self._list_index - 1]\n\n    def _extract_sublist(self, listing):\n        if isinstance(listing, list):\n            return listing[1]  # for submission duplicates\n        elif isinstance(listing, dict):\n            classes = [FlairListing, ModNoteListing]\n\n            for listing_type in classes:\n                if listing_type.CHILD_ATTRIBUTE in listing:\n                    return listing_type(self._reddit, listing)\n            else:\n                raise ValueError(\n                    \"The generator returned a dictionary PRAW didn't recognize.\"\n                    \" File a bug report at PRAW.\"\n                )\n        return listing\n\n    def _next_batch(self):\n        if self._exhausted:\n            raise StopIteration()\n\n        self._listing = self._reddit.get(self.url, params=self.params)\n        self._listing = self._extract_sublist(self._listing)\n        self._list_index = 0\n\n        if not self._listing:\n            raise StopIteration()\n\n        if self._listing.after and self._listing.after != self.params.get(\"after\"):\n            self.params[\"after\"] = self._listing.after\n        else:\n            self._exhausted = True\n", "path": "praw/models/listing/generator.py"}, {"content": "\"\"\"Provide the Listing class.\"\"\"\nfrom typing import Any, Optional\n\nfrom ..base import PRAWBase\n\n\nclass Listing(PRAWBase):\n    \"\"\"A listing is a collection of :class:`.RedditBase` instances.\"\"\"\n\n    CHILD_ATTRIBUTE = \"children\"\n\n    def __len__(self) -> int:\n        \"\"\"Return the number of items in the Listing.\"\"\"\n        return len(getattr(self, self.CHILD_ATTRIBUTE))\n\n    def __getitem__(self, index: int) -> Any:\n        \"\"\"Return the item at position index in the list.\"\"\"\n        return getattr(self, self.CHILD_ATTRIBUTE)[index]\n\n    def __setattr__(self, attribute: str, value: Any):\n        \"\"\"Objectify the ``CHILD_ATTRIBUTE`` attribute.\"\"\"\n        if attribute == self.CHILD_ATTRIBUTE:\n            value = self._reddit._objector.objectify(value)\n        super().__setattr__(attribute, value)\n\n\nclass FlairListing(Listing):\n    \"\"\"Special Listing for handling flair lists.\"\"\"\n\n    CHILD_ATTRIBUTE = \"users\"\n\n    @property\n    def after(self) -> Optional[Any]:\n        \"\"\"Return the next attribute or ``None``.\"\"\"\n        return getattr(self, \"next\", None)\n\n\nclass ModeratorListing(Listing):\n    \"\"\"Special Listing for handling moderator lists.\"\"\"\n\n    CHILD_ATTRIBUTE = \"moderators\"\n\n\nclass ModNoteListing(Listing):\n    \"\"\"Special Listing for handling :class:`.ModNote` lists.\"\"\"\n\n    CHILD_ATTRIBUTE = \"mod_notes\"\n\n    @property\n    def after(self) -> Optional[Any]:\n        \"\"\"Return the next attribute or None.\"\"\"\n        if not getattr(self, \"has_next_page\", True):\n            return None\n        return getattr(self, \"end_cursor\", None)\n\n\nclass ModmailConversationsListing(Listing):\n    \"\"\"Special Listing for handling :class:`.ModmailConversation` lists.\"\"\"\n\n    CHILD_ATTRIBUTE = \"conversations\"\n\n    @property\n    def after(self) -> Optional[str]:\n        \"\"\"Return the next attribute or ``None``.\"\"\"\n        try:\n            return self.conversations[-1].id\n        except IndexError:\n            return None\n", "path": "praw/models/listing/listing.py"}], "after_files": [{"content": "\"\"\"Provide the ListingGenerator class.\"\"\"\nfrom copy import deepcopy\nfrom typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Union\n\nfrom ..base import PRAWBase\nfrom .listing import FlairListing, ModNoteListing\n\nif TYPE_CHECKING:  # pragma: no cover\n    import praw\n\n\nclass ListingGenerator(PRAWBase, Iterator):\n    \"\"\"Instances of this class generate :class:`.RedditBase` instances.\n\n    .. warning::\n\n        This class should not be directly utilized. Instead, you will find a number of\n        methods that return instances of the class here_.\n\n    .. _here: https://praw.readthedocs.io/en/latest/search.html?q=ListingGenerator\n\n    \"\"\"\n\n    def __init__(\n        self,\n        reddit: \"praw.Reddit\",\n        url: str,\n        limit: int = 100,\n        params: Optional[Dict[str, Union[str, int]]] = None,\n    ):\n        \"\"\"Initialize a :class:`.ListingGenerator` instance.\n\n        :param reddit: An instance of :class:`.Reddit`.\n        :param url: A URL returning a Reddit listing.\n        :param limit: The number of content entries to fetch. If ``limit`` is ``None``,\n            then fetch as many entries as possible. Most of Reddit's listings contain a\n            maximum of 1000 items, and are returned 100 at a time. This class will\n            automatically issue all necessary requests (default: ``100``).\n        :param params: A dictionary containing additional query string parameters to\n            send with the request.\n\n        \"\"\"\n        super().__init__(reddit, _data=None)\n        self._exhausted = False\n        self._listing = None\n        self._list_index = None\n        self.limit = limit\n        self.params = deepcopy(params) if params else {}\n        self.params[\"limit\"] = limit or 1024\n        self.url = url\n        self.yielded = 0\n\n    def __iter__(self) -> Iterator[Any]:\n        \"\"\"Permit :class:`.ListingGenerator` to operate as an iterator.\"\"\"\n        return self\n\n    def __next__(self) -> Any:\n        \"\"\"Permit :class:`.ListingGenerator` to operate as a generator.\"\"\"\n        if self.limit is not None and self.yielded >= self.limit:\n            raise StopIteration()\n\n        if self._listing is None or self._list_index >= len(self._listing):\n            self._next_batch()\n\n        self._list_index += 1\n        self.yielded += 1\n        return self._listing[self._list_index - 1]\n\n    def _extract_sublist(self, listing):\n        if isinstance(listing, list):\n            return listing[1]  # for submission duplicates\n        elif isinstance(listing, dict):\n            classes = [FlairListing, ModNoteListing]\n\n            for listing_type in classes:\n                if listing_type.CHILD_ATTRIBUTE in listing:\n                    return listing_type(self._reddit, listing)\n            else:\n                raise ValueError(\n                    \"The generator returned a dictionary PRAW didn't recognize.\"\n                    \" File a bug report at PRAW.\"\n                )\n        return listing\n\n    def _next_batch(self):\n        if self._exhausted:\n            raise StopIteration()\n\n        self._listing = self._reddit.get(self.url, params=self.params)\n        self._listing = self._extract_sublist(self._listing)\n        self._list_index = 0\n\n        if not self._listing:\n            raise StopIteration()\n\n        if self._listing.after and self._listing.after != self.params.get(\n            self._listing.AFTER_PARAM\n        ):\n            self.params[self._listing.AFTER_PARAM] = self._listing.after\n        else:\n            self._exhausted = True\n", "path": "praw/models/listing/generator.py"}, {"content": "\"\"\"Provide the Listing class.\"\"\"\nfrom typing import Any, Optional\n\nfrom ..base import PRAWBase\n\n\nclass Listing(PRAWBase):\n    \"\"\"A listing is a collection of :class:`.RedditBase` instances.\"\"\"\n\n    AFTER_PARAM = \"after\"\n    CHILD_ATTRIBUTE = \"children\"\n\n    def __len__(self) -> int:\n        \"\"\"Return the number of items in the Listing.\"\"\"\n        return len(getattr(self, self.CHILD_ATTRIBUTE))\n\n    def __getitem__(self, index: int) -> Any:\n        \"\"\"Return the item at position index in the list.\"\"\"\n        return getattr(self, self.CHILD_ATTRIBUTE)[index]\n\n    def __setattr__(self, attribute: str, value: Any):\n        \"\"\"Objectify the ``CHILD_ATTRIBUTE`` attribute.\"\"\"\n        if attribute == self.CHILD_ATTRIBUTE:\n            value = self._reddit._objector.objectify(value)\n        super().__setattr__(attribute, value)\n\n\nclass FlairListing(Listing):\n    \"\"\"Special Listing for handling flair lists.\"\"\"\n\n    CHILD_ATTRIBUTE = \"users\"\n\n    @property\n    def after(self) -> Optional[Any]:\n        \"\"\"Return the next attribute or ``None``.\"\"\"\n        return getattr(self, \"next\", None)\n\n\nclass ModeratorListing(Listing):\n    \"\"\"Special Listing for handling moderator lists.\"\"\"\n\n    CHILD_ATTRIBUTE = \"moderators\"\n\n\nclass ModNoteListing(Listing):\n    \"\"\"Special Listing for handling :class:`.ModNote` lists.\"\"\"\n\n    AFTER_PARAM = \"before\"\n    CHILD_ATTRIBUTE = \"mod_notes\"\n\n    @property\n    def after(self) -> Optional[Any]:\n        \"\"\"Return the next attribute or None.\"\"\"\n        if not getattr(self, \"has_next_page\", True):\n            return None\n        return getattr(self, \"end_cursor\", None)\n\n\nclass ModmailConversationsListing(Listing):\n    \"\"\"Special Listing for handling :class:`.ModmailConversation` lists.\"\"\"\n\n    CHILD_ATTRIBUTE = \"conversations\"\n\n    @property\n    def after(self) -> Optional[str]:\n        \"\"\"Return the next attribute or ``None``.\"\"\"\n        try:\n            return self.conversations[-1].id\n        except IndexError:\n            return None\n", "path": "praw/models/listing/listing.py"}]}