• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

praw-dev / praw / 3768928224

pending completion
3768928224

Pull #1923

github

GitHub
Merge 33b610e6e into ffe9f71d6
Pull Request #1923: Improve tests, clean up test code, and sort test functions/classes

4109 of 4109 relevant lines covered (100.0%)

4.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/praw/models/helpers.py
1
"""Provide the helper classes."""
2
from json import dumps
4✔
3
from typing import TYPE_CHECKING, Generator, List, Optional, Union
4✔
4

5
from ..const import API_PATH
4✔
6
from ..util import _deprecate_args
4✔
7
from .base import PRAWBase
4✔
8
from .reddit.draft import Draft
4✔
9
from .reddit.live import LiveThread
4✔
10
from .reddit.multi import Multireddit, Subreddit
4✔
11

12
if TYPE_CHECKING:  # pragma: no cover
13
    import praw
14

15

16
class DraftHelper(PRAWBase):
4✔
17
    r"""Provide a set of functions to interact with :class:`.Draft` instances.
18

19
    .. note::
20

21
        The methods provided by this class will only work on the currently authenticated
22
        user's :class:`.Draft`\ s.
23

24
    """
25

26
    def __call__(
4✔
27
        self, draft_id: Optional[str] = None
28
    ) -> Union[List["praw.models.Draft"], "praw.models.Draft"]:
29
        """Return a list of :class:`.Draft` instances.
30

31
        :param draft_id: When provided, return :class:`.Draft` instance (default:
32
            ``None``).
33

34
        :returns: A :class:`.Draft` instance if ``draft_id`` is provided. Otherwise, a
35
            list of :class:`.Draft` objects.
36

37
        .. note::
38

39
            Drafts fetched using a specific draft ID are lazily loaded, so you might
40
            have to access an attribute to get all the expected attributes.
41

42
        This method can be used to fetch a specific draft by ID, like so:
43

44
        .. code-block:: python
45

46
            draft_id = "124862bc-e1e9-11eb-aa4f-e68667a77cbb"
47
            draft = reddit.drafts(draft_id)
48
            print(draft)
49

50
        """
51
        if draft_id is not None:
4✔
52
            return Draft(self._reddit, id=draft_id)
4✔
53
        return self._draft_list()
4✔
54

55
    def _draft_list(self) -> List["praw.models.Draft"]:
4✔
56
        """Get a list of :class:`.Draft` instances.
57

58
        :returns: A list of :class:`.Draft` instances.
59

60
        """
61
        return self._reddit.get(API_PATH["drafts"], params={"md_body": True})
4✔
62

63
    def create(
4✔
64
        self,
65
        *,
66
        flair_id: Optional[str] = None,
67
        flair_text: Optional[str] = None,
68
        is_public_link: bool = False,
69
        nsfw: bool = False,
70
        original_content: bool = False,
71
        selftext: Optional[str] = None,
72
        send_replies: bool = True,
73
        spoiler: bool = False,
74
        subreddit: Optional[
75
            Union[str, "praw.models.Subreddit", "praw.models.UserSubreddit"]
76
        ] = None,
77
        title: Optional[str] = None,
78
        url: Optional[str] = None,
79
        **draft_kwargs,
80
    ) -> "praw.models.Draft":
81
        """Create a new :class:`.Draft`.
82

83
        :param flair_id: The flair template to select (default: ``None``).
84
        :param flair_text: If the template's ``flair_text_editable`` value is ``True``,
85
            this value will set a custom text (default: ``None``). ``flair_id`` is
86
            required when ``flair_text`` is provided.
87
        :param is_public_link: Whether to enable public viewing of the draft before it
88
            is submitted (default: ``False``).
89
        :param nsfw: Whether the draft should be marked NSFW (default: ``False``).
90
        :param original_content: Whether the submission should be marked as original
91
            content (default: ``False``).
92
        :param selftext: The Markdown formatted content for a text submission draft. Use
93
            ``None`` to make a title-only submission draft (default: ``None``).
94
            ``selftext`` can not be provided if ``url`` is provided.
95
        :param send_replies: When ``True``, messages will be sent to the submission
96
            author when comments are made to the submission (default: ``True``).
97
        :param spoiler: Whether the submission should be marked as a spoiler (default:
98
            ``False``).
99
        :param subreddit: The subreddit to create the draft for. This accepts a
100
            subreddit display name, :class:`.Subreddit` object, or
101
            :class:`.UserSubreddit` object. If ``None``, the :class:`.UserSubreddit` of
102
            currently authenticated user will be used (default: ``None``).
103
        :param title: The title of the draft (default: ``None``).
104
        :param url: The URL for a ``link`` submission draft (default: ``None``). ``url``
105
            can not be provided if ``selftext`` is provided.
106

107
        Additional keyword arguments can be provided to handle new parameters as Reddit
108
        introduces them.
109

110
        :returns: The new :class:`.Draft` object.
111

112
        """
113
        if selftext and url:
4✔
114
            raise TypeError("Exactly one of 'selftext' or 'url' must be provided.")
4✔
115
        if isinstance(subreddit, str):
4✔
116
            subreddit = self._reddit.subreddit(subreddit)
4✔
117

118
        data = Draft._prepare_data(
4✔
119
            flair_id=flair_id,
120
            flair_text=flair_text,
121
            is_public_link=is_public_link,
122
            nsfw=nsfw,
123
            original_content=original_content,
124
            selftext=selftext,
125
            send_replies=send_replies,
126
            spoiler=spoiler,
127
            subreddit=subreddit,
128
            title=title,
129
            url=url,
130
            **draft_kwargs,
131
        )
132
        return self._reddit.post(API_PATH["draft"], data=data)
4✔
133

134

135
class LiveHelper(PRAWBase):
4✔
136
    r"""Provide a set of functions to interact with :class:`.LiveThread`\ s."""
137

138
    def __call__(
4✔
139
        self, id: str
140
    ) -> "praw.models.LiveThread":  # pylint: disable=invalid-name,redefined-builtin
141
        """Return a new lazy instance of :class:`.LiveThread`.
142

143
        This method is intended to be used as:
144

145
        .. code-block:: python
146

147
            livethread = reddit.live("ukaeu1ik4sw5")
148

149
        :param id: A live thread ID, e.g., ``ukaeu1ik4sw5``.
150

151
        """
152
        return LiveThread(self._reddit, id=id)
4✔
153

154
    def info(self, ids: List[str]) -> Generator["praw.models.LiveThread", None, None]:
4✔
155
        """Fetch information about each live thread in ``ids``.
156

157
        :param ids: A list of IDs for a live thread.
158

159
        :returns: A generator that yields :class:`.LiveThread` instances.
160

161
        Live threads that cannot be matched will not be generated. Requests will be
162
        issued in batches for each 100 IDs.
163

164
        .. warning::
165

166
            Unlike :meth:`.Reddit.info`, the output of this method may not reflect the
167
            order of input.
168

169
        Usage:
170

171
        .. code-block:: python
172

173
            ids = ["3rgnbke2rai6hen7ciytwcxadi", "sw7bubeycai6hey4ciytwamw3a", "t8jnufucss07"]
174
            for thread in reddit.live.info(ids):
175
                print(thread.title)
176

177
        """
178
        if not isinstance(ids, list):
4✔
179
            raise TypeError("ids must be a list")
4✔
180

181
        def generator():
4✔
182
            for position in range(0, len(ids), 100):
4✔
183
                ids_chunk = ids[position : position + 100]
4✔
184
                url = API_PATH["live_info"].format(ids=",".join(ids_chunk))
4✔
185
                params = {"limit": 100}  # 25 is used if not specified
4✔
186
                for result in self._reddit.get(url, params=params):
4✔
187
                    yield result
4✔
188

189
        return generator()
4✔
190

191
    @_deprecate_args("title", "description", "nsfw", "resources")
4✔
192
    def create(
4✔
193
        self,
194
        title: str,
195
        *,
196
        description: Optional[str] = None,
197
        nsfw: bool = False,
198
        resources: str = None,
199
    ) -> "praw.models.LiveThread":
200
        """Create a new :class:`.LiveThread`.
201

202
        :param title: The title of the new :class:`.LiveThread`.
203
        :param description: The new :class:`.LiveThread`'s description.
204
        :param nsfw: Indicate whether this thread is not safe for work (default:
205
            ``False``).
206
        :param resources: Markdown formatted information that is useful for the
207
            :class:`.LiveThread`.
208

209
        :returns: The new :class:`.LiveThread` object.
210

211
        """
212
        return self._reddit.post(
4✔
213
            API_PATH["livecreate"],
214
            data={
215
                "description": description,
216
                "nsfw": nsfw,
217
                "resources": resources,
218
                "title": title,
219
            },
220
        )
221

222
    def now(self) -> Optional["praw.models.LiveThread"]:
4✔
223
        """Get the currently featured live thread.
224

225
        :returns: The :class:`.LiveThread` object, or ``None`` if there is no currently
226
            featured live thread.
227

228
        Usage:
229

230
        .. code-block:: python
231

232
            thread = reddit.live.now()  # LiveThread object or None
233

234
        """
235
        return self._reddit.get(API_PATH["live_now"])
4✔
236

237

238
class MultiredditHelper(PRAWBase):
4✔
239
    """Provide a set of functions to interact with multireddits."""
240

241
    @_deprecate_args("redditor", "name")
4✔
242
    def __call__(
4✔
243
        self, *, name: str, redditor: Union[str, "praw.models.Redditor"]
244
    ) -> "praw.models.Multireddit":
245
        """Return a lazy instance of :class:`.Multireddit`.
246

247
        :param name: The name of the multireddit.
248
        :param redditor: A redditor name or :class:`.Redditor` instance who owns the
249
            multireddit.
250

251
        """
252
        path = f"/user/{redditor}/m/{name}"
4✔
253
        return Multireddit(self._reddit, _data={"name": name, "path": path})
4✔
254

255
    @_deprecate_args(
4✔
256
        "display_name",
257
        "subreddits",
258
        "description_md",
259
        "icon_name",
260
        "key_color",
261
        "visibility",
262
        "weighting_scheme",
263
    )
264
    def create(
4✔
265
        self,
266
        *,
267
        description_md: Optional[str] = None,
268
        display_name: str,
269
        icon_name: Optional[str] = None,
270
        key_color: Optional[str] = None,
271
        subreddits: Union[str, "praw.models.Subreddit"],
272
        visibility: str = "private",
273
        weighting_scheme: str = "classic",
274
    ) -> "praw.models.Multireddit":
275
        """Create a new :class:`.Multireddit`.
276

277
        :param display_name: The display name for the new multireddit.
278
        :param subreddits: Subreddits to add to the new multireddit. Can be a list of
279
            either :class:`.Subreddit` instances or subreddit display names.
280
        :param description_md: Description for the new multireddit, formatted in
281
            markdown.
282
        :param icon_name: Can be one of: ``"art and design"``, ``"ask"``, ``"books"``,
283
            ``"business"``, ``"cars"``, ``"comics"``, ``"cute animals"``, ``"diy"``,
284
            ``"entertainment"``, ``"food and drink"``, ``"funny"``, ``"games"``,
285
            ``"grooming"``, ``"health"``, ``"life advice"``, ``"military"``, ``"models
286
            pinup"``, ``"music"``, ``"news"``, ``"philosophy"``, ``"pictures and
287
            gifs"``, ``"science"``, ``"shopping"``, ``"sports"``, ``"style"``,
288
            ``"tech"``, ``"travel"``, ``"unusual stories"``, ``"video"``, or ``None``.
289
        :param key_color: RGB hex color code of the form ``"#FFFFFF"``.
290
        :param visibility: Can be one of: ``"hidden"``, ``"private"``, or ``"public"``
291
            (default: ``"private"``).
292
        :param weighting_scheme: Can be one of: ``"classic"`` or ``"fresh"`` (default:
293
            ``"classic"``).
294

295
        :returns: The new :class:`.Multireddit` object.
296

297
        """
298
        model = {
4✔
299
            "description_md": description_md,
300
            "display_name": display_name,
301
            "icon_name": icon_name,
302
            "key_color": key_color,
303
            "subreddits": [{"name": str(sub)} for sub in subreddits],
304
            "visibility": visibility,
305
            "weighting_scheme": weighting_scheme,
306
        }
307
        return self._reddit.post(
4✔
308
            API_PATH["multireddit_base"], data={"model": dumps(model)}
309
        )
310

311

312
class SubredditHelper(PRAWBase):
4✔
313
    """Provide a set of functions to interact with Subreddits."""
314

315
    def __call__(self, display_name: str) -> "praw.models.Subreddit":
4✔
316
        """Return a lazy instance of :class:`.Subreddit`.
317

318
        :param display_name: The name of the subreddit.
319

320
        """
321
        lower_name = display_name.lower()
4✔
322

323
        if lower_name == "random":
4✔
324
            return self._reddit.random_subreddit()
4✔
325
        if lower_name == "randnsfw":
4✔
326
            return self._reddit.random_subreddit(nsfw=True)
4✔
327

328
        return Subreddit(self._reddit, display_name=display_name)
4✔
329

330
    @_deprecate_args("name", "title", "link_type", "subreddit_type", "wikimode")
4✔
331
    def create(
4✔
332
        self,
333
        name: str,
334
        *,
335
        link_type: str = "any",
336
        subreddit_type: str = "public",
337
        title: Optional[str] = None,
338
        wikimode: str = "disabled",
339
        **other_settings: Optional[str],
340
    ) -> "praw.models.Subreddit":
341
        """Create a new :class:`.Subreddit`.
342

343
        :param name: The name for the new subreddit.
344
        :param link_type: The types of submissions users can make. One of ``"any"``,
345
            ``"link"``, or ``"self"`` (default: ``"any"``).
346
        :param subreddit_type: One of ``"archived"``, ``"employees_only"``,
347
            ``"gold_only"``, ``"gold_restricted"``, ``"private"``, ``"public"``, or
348
            ``"restricted"`` (default: ``"public"``).
349
        :param title: The title of the subreddit. When ``None`` or ``""`` use the value
350
            of ``name``.
351
        :param wikimode: One of ``"anyone"``, ``"disabled"``, or ``"modonly"`` (default:
352
            ``"disabled"``).
353

354
        Any keyword parameters not provided, or set explicitly to ``None``, will take on
355
        a default value assigned by the Reddit server.
356

357
        .. seealso::
358

359
            :meth:`~.SubredditModeration.update` for documentation of other available
360
            settings.
361

362
        """
363
        Subreddit._create_or_update(
4✔
364
            _reddit=self._reddit,
365
            link_type=link_type,
366
            name=name,
367
            subreddit_type=subreddit_type,
368
            title=title or name,
369
            wikimode=wikimode,
370
            **other_settings,
371
        )
372
        return self(name)
4✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc