Passed
Pull Request — main (#237)
by
unknown
01:29
created

UserMessage.delete()   A

Complexity

Conditions 1

Size

Total Lines 9
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 9
rs 10
c 0
b 0
f 0
cc 1
nop 1
1
# Copyright Pincer 2021-Present
0 ignored issues
show
introduced by
Missing module docstring
Loading history...
2
# Full MIT License can be found in `LICENSE` at the project root.
3
4
from __future__ import annotations
5
6
from dataclasses import dataclass
7
from enum import Enum, IntEnum
8
from re import sub
9
from typing import TYPE_CHECKING
10
11
from .attachment import Attachment
12
from .component import MessageComponent
13
from .embed import Embed
14
from .reaction import Reaction
15
from .reference import MessageReference
16
from .sticker import StickerItem
17
from ..app.application import Application
18
from ..app.interaction_base import MessageInteraction
19
from ..guild.member import GuildMember
20
from ..guild.role import Role
21
from ..user.user import User
22
from ..._config import GatewayConfig
23
from ...utils.api_object import APIObject
0 ignored issues
show
introduced by
Cannot import 'utils.api_object' due to syntax error 'invalid syntax (<unknown>, line 80)'
Loading history...
Bug introduced by
The name api_object does not seem to exist in module pincer.utils.
Loading history...
24
from ...utils.conversion import construct_client_dict
25
from ...utils.snowflake import Snowflake
26
from ...utils.types import MISSING
27
28
if TYPE_CHECKING:
29
    from typing import Any, List, Optional, Union, Generator
30
31
    from ..guild.channel import Channel, ChannelMention
0 ignored issues
show
Bug introduced by
The name channel does not seem to exist in module pincer.objects.guild.
Loading history...
introduced by
Cannot import 'guild.channel' due to syntax error 'invalid syntax (<unknown>, line 251)'
Loading history...
32
    from ...utils.types import APINullable
33
    from ...utils.timestamp import Timestamp
0 ignored issues
show
Bug introduced by
The name timestamp does not seem to exist in module pincer.utils.
Loading history...
introduced by
Cannot import 'utils.timestamp' due to syntax error 'invalid syntax (<unknown>, line 103)'
Loading history...
34
35
36
class AllowedMentionTypes(str, Enum):
37
    """The allowed mentions.
38
39
    Attributes
40
    ----------
41
    ROLES:
42
        Controls role mentions
43
    USERS:
44
        Controls user mentions
45
    EVERYONE:
46
        Controls @everyone and @here mentions
47
    """
48
    ROLES = "roles"
49
    USERS = "users"
50
    EVERYONE = "everyone"
51
52
53
@dataclass
54
class AllowedMentions(APIObject):
55
    """Represents the entities the client can mention
56
57
    Attributes
58
    ----------
59
    parse: List[:class:`~pincer.objects.message.user_message.AllowedMentionTypes`]
60
        An array of allowed mention types to parse from the content.
61
    roles: List[Union[:class:`~pincer.objects.guild.role.Role`, :class:`~pincer.utils.snowflake.Snowflake`]]
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (108/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
62
        List of ``Role`` objects or snowflakes of allowed mentions.
63
    users: List[Union[:class:`~pincer.objects.user.user.User` :class:`~pincer.utils.snowflake.Snowflake`]]
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (106/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
64
        List of ``user`` objects or snowflakes of allowed mentions.
65
    reply: :class:`bool`
66
        If replies should mention the author.
67
        |default| :data:`True`
68
    """  # noqa: E501
69
70
    parse: List[AllowedMentionTypes]
71
    roles: List[Union[Role, Snowflake]]
72
    users: List[Union[User, Snowflake]]
73
    reply: bool = True
74
75
    def to_dict(self):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
76
        def get_str_id(obj: Union[Snowflake, User, Role]) -> str:
77
            if hasattr(obj, "id"):
78
                obj = obj.id
79
80
            return str(obj)
81
82
        return {
83
            "parse": self.parse,
84
            "roles": list(map(get_str_id, self.roles)),
85
            "users": list(map(get_str_id, self.users)),
86
            "replied_user": self.reply
87
        }
88
89
90
class MessageActivityType(IntEnum):
91
    """The activity people can perform on a rich presence activity.
92
93
    Such an activity could for example be a spotify listen.
94
95
    Attributes
96
    ----------
97
    JOIN:
98
        Invite to join.
99
    SPECTATE:
100
        Invite to spectate.
101
    LISTEN:
102
        Invite to listen along.
103
    JOIN_REQUEST:
104
        Request to join.
105
    """
106
    JOIN = 1
107
    SPECTATE = 2
108
    LISTEN = 3
109
    JOIN_REQUEST = 5
110
111
112
class MessageFlags(IntEnum):
113
    """Special message properties.
114
115
    Attributes
116
    ----------
117
    CROSSPOSTED:
118
        The message has been published to subscribed
119
        channels (via Channel Following)
120
    IS_CROSSPOST:
121
        This message originated from a message
122
        in another channel (via Channel Following)
123
    SUPPRESS_EMBEDS:
124
        Do not include any embeds when serializing this message
125
    SOURCE_MESSAGE_DELETED:
126
        The source message for this crosspost
127
        has been deleted (via Channel Following)
128
    URGENT:
129
        This message came from the urgent message system
130
    HAS_THREAD:
131
        This message has an associated thread,
132
        with the same id as the message
133
    EPHEMERAL:
134
        This message is only visible to the user
135
        who invoked the Interaction
136
    LOADING:
137
        This message is an Interaction
138
        Response and the bot is "thinking"
139
    """
140
    CROSSPOSTED = 1 << 0
141
    IS_CROSSPOST = 1 << 1
142
    SUPPRESS_EMBEDS = 1 << 2
143
    SOURCE_MESSAGE_DELETED = 1 << 3
144
    URGENT = 1 << 4
145
    HAS_THREAD = 1 << 5
146
    EPHEMERAL = 1 << 6
147
    LOADING = 1 << 7
148
149
150
class MessageType(IntEnum):
151
    """Represents the type of the message.
152
153
    Attributes
154
    ----------
155
    DEFAULT:
156
        Normal message.
157
    RECIPIENT_ADD:
158
        Recipient is added.
159
    RECIPIENT_REMOVE:
160
        Recipient is removed.
161
    CALL:
162
        A call is being made.
163
    CHANNEL_NAME_CHANGE:
164
        The group channel name is changed.
165
    CHANNEL_ICON_CHANGE:
166
        The group channel icon is changed.
167
    CHANNEL_PINNED_MESSAGE:
168
        A message is pinned.
169
    GUILD_MEMBER_JOIN:
170
        A member joined.
171
    USER_PREMIUM_GUILD_SUBSCRIPTION:
172
        A boost.
173
    USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1:
174
        A boost that reached tier 1.
175
    USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2:
176
        A boost that reached tier 2.
177
    USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3:
178
        A boost that reached tier 3.
179
    CHANNEL_FOLLOW_ADD:
180
        A channel is subscribed to.
181
    GUILD_DISCOVERY_DISQUALIFIED:
182
        The guild is disqualified from discovery,
183
    GUILD_DISCOVERY_REQUALIFIED:
184
        The guild is requalified for discovery.
185
    GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING:
186
        Warning about discovery violations.
187
    GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING:
188
        Final warning about discovery violations.
189
    THREAD_CREATED:
190
        A thread is created.
191
    REPLY:
192
        A message reply.
193
    APPLICATION_COMMAND:
194
        Slash command is used and responded to.
195
    THREAD_STARTER_MESSAGE:
196
        The initial message in a thread when its created off a message.
197
    GUILD_INVITE_REMINDER:
198
        ??
199
    """
200
    DEFAULT = 0
201
    RECIPIENT_ADD = 1
202
    RECIPIENT_REMOVE = 2
203
    CALL = 3
204
    CHANNEL_NAME_CHANGE = 4
205
    CHANNEL_ICON_CHANGE = 5
206
    CHANNEL_PINNED_MESSAGE = 6
207
    GUILD_MEMBER_JOIN = 7
208
    USER_PREMIUM_GUILD_SUBSCRIPTION = 8
209
    USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1 = 9
210
    USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2 = 10
211
    USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3 = 11
212
    CHANNEL_FOLLOW_ADD = 12
213
    GUILD_DISCOVERY_DISQUALIFIED = 14
214
    GUILD_DISCOVERY_REQUALIFIED = 15
215
    GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING = 16
216
    GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING = 17
217
    THREAD_CREATED = 18
218
    REPLY = 19
219
    APPLICATION_COMMAND = 20
220
221
    if GatewayConfig.version < 8:
222
        REPLY = 0
223
        APPLICATION_COMMAND = 0
224
225
    if GatewayConfig.version >= 9:
226
        THREAD_STARTER_MESSAGE = 21
227
228
    GUILD_INVITE_REMINDER = 22
229
230
231
@dataclass
232
class MessageActivity(APIObject):
233
    """Represents a Discord Message Activity object
234
235
    Attributes
236
    ----------
237
    type: :class:`~pincer.objects.message.user_message.MessageActivity`
238
        type of message activity
239
    party_id: APINullable[:class:`str`]
240
        party_id from a Rich Presence event
241
    """
242
    type: MessageActivityType
243
    party_id: APINullable[str] = MISSING
244
245
246
@dataclass
0 ignored issues
show
best-practice introduced by
Too many instance attributes (30/7)
Loading history...
247
class UserMessage(APIObject):
248
    """Represents a message sent in a channel within Discord.
249
250
    Attributes
251
    ----------
252
    id: :class:`~pincer.utils.snowflake.Snowflake`
253
        Ud of the message
254
    channel_id: :class:`~pincer.utils.snowflake.Snowflake`
255
        Id of the channel the message was sent in
256
    author: :class:`~pincer.objects.user.user.User`
257
        The author of this message (not guaranteed to be a valid user)
258
    content: :class:`str`
259
        Contents of the message
260
    timestamp: :class:`~pincer.utils.timestamp.Timestamp`
261
        When this message was sent
262
    edited_timestamp: Optional[:class:`~pincer.utils.timestamp.Timestamp`]
263
        When this message was edited (or null if never)
264
    tts: :class:`bool`
265
        Whether this was a TTS message
266
    mention_everyone: :class:`bool`
267
        Whether this message mentions everyone
268
    mentions: List[:class:`~pincer.objects.guild.member.GuildMember`]
269
        Users specifically mentioned in the message
270
    mention_roles: List[:class:`~pincer.objects.guild.role.Role`]
271
        Roles specifically mentioned in this message
272
    attachments: List[:class:`~pincer.objects.message.attachment.Attachment`]
273
        Any attached files
274
    embeds: List[:class:`~pincer.objects.message.embed.Embed`]
275
        Any embedded content
276
    pinned: :class:`bool`
277
        Whether this message is pinned
278
    type: :class:`~pincer.objects.message.user_message.MessageType`
279
        Type of message
280
    mention_channels: APINullable[List[:class:`~pincer.objects.guild.channel.Channel`]]
281
        Channels specifically mentioned in this message
282
    guild_id: APINullable[:class:`~pincer.utils.snowflake.Snowflake`]
283
        Id of the guild the message was sent in
284
    member: APINullable[:class:`~pincer.objects.guild.member.PartialGuildMember`]
285
        Member properties for this message's author
286
    reactions: APINullable[List[:class:`~pincer.objects.message.reaction.Reaction`]]
287
        Reactions to the message
288
    nonce: APINullable[Union[:class:`int`, :class:`str`]]
289
        User for validating a message was sent
290
    webhook_id: APINullable[:class:`~pincer.utils.snowflake.Snowflake`]
291
        If the message is generated by a webhook,
292
        this is the webhook's id
293
    activity: APINullable[:class:`~pincer.objects.message.user_message.MessageActivity`]
294
        Sent with Rich Presence-related chat embeds
295
    application: APINullable[:class:`~pincer.objects.app.application.Application`]
296
        Sent with Rich Presence-related chat embeds
297
    application_id: APINullable[:class:`~pincer.utils.snowflake.Snowflake`]
298
        If the message is a response to an Interaction,
299
        this is the id of the interaction's application
300
    message_reference: APINullable[:class:`~pincer.objects.message.reference.MessageReference`]
301
        Data showing the source of a crosspost,
302
        channel follow add, pin, or reply message
303
    flags: APINullable[:class:`~pincer.objects.message.user_message.MessageFlags`]
304
        Message flags combined as a bitfield
305
    referenced_message: APINullable[Optional[:class:`~pincer.objects.message.user_message.UserMessage`]]
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (104/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
306
        The message associated with the message_reference
307
    interaction: APINullable[:class:`~pincer.objects.app.interaction_base.MessageInteraction`]
308
        Sent if the message is a response to an Interaction
309
    thread: APINullable[:class:`~pincer.objects.guild.channel.Channel`]
310
        The thread that was started from this message,
311
        includes thread member object
312
    components: APINullable[List[:class:`~pincer.objects.message.component.MessageComponent`]]
313
        Sent if the message contains components like buttons,
314
        action rows, or other interactive components
315
    sticker_items: APINullable[List[:class:`~pincer.objects.message.sticker.StickerItem`]]
316
        Sent if the message contains stickers
317
    """
318
    # noqa: E501
319
320
    id: Snowflake
321
    channel_id: Snowflake
322
    author: User
323
    content: str
324
    timestamp: Timestamp
325
    tts: bool
326
    mention_everyone: bool
327
    mentions: List[GuildMember]
328
    mention_roles: List[Role]
329
    attachments: List[Attachment]
330
    embeds: List[Embed]
331
    pinned: bool
332
    type: MessageType
333
334
    edited_timestamp: APINullable[Timestamp] = MISSING
335
    mention_channels: APINullable[List[ChannelMention]] = MISSING
336
    guild_id: APINullable[Snowflake] = MISSING
337
    member: APINullable[GuildMember] = MISSING
338
    reactions: APINullable[List[Reaction]] = MISSING
339
    nonce: APINullable[Union[int, str]] = MISSING
340
    webhook_id: APINullable[Snowflake] = MISSING
341
    activity: APINullable[MessageActivity] = MISSING
342
    application: APINullable[Application] = MISSING
343
    application_id: APINullable[Snowflake] = MISSING
344
    message_reference: APINullable[MessageReference] = MISSING
345
    flags: APINullable[MessageFlags] = MISSING
346
    referenced_message: APINullable[Optional[UserMessage]] = MISSING
347
    interaction: APINullable[MessageInteraction] = MISSING
348
    thread: APINullable[Channel] = MISSING
349
    components: APINullable[List[MessageComponent]] = MISSING
350
    sticker_items: APINullable[List[StickerItem]] = MISSING
351
352
    def __str__(self):
353
        return self.content
354
355
    async def get_most_recent(self):
356
        """|coro|
357
358
        Certain Discord methods don't return the message object data after its
359
        updated. This function can be run to get the most recent version of the
360
        message object.
361
        """
362
363
        return self.from_dict(
364
            construct_client_dict(
365
                self._client,
366
                await self._http.get(
367
                    f"/channels/{self.channel_id}/messages/{self.id}"
368
                )
369
            )
370
        )
371
372
    async def react(self, emoji: str):
373
        """|coro|
374
375
        Create a reaction for the message. Requires the
376
        ``READ_MESSAGE_HISTORY` intent. ``ADD_REACTIONS`` intent is required if
377
        nobody else has reacted using the emoji.
378
379
        Parameters
380
        ----------
381
        emoji: :class:`str`
382
            Character for emoji. Does not need to be URL encoded.
383
        """
384
385
        await self._http.put(
386
            f"/channels/{self.channel_id}/messages/{self.id}/reactions/{emoji}/@me"
387
        )
388
389
    async def unreact(self, emoji: str):
390
        """|coro|
391
392
        Delete a reaction the current user has made for the message.
393
394
        Parameters
395
        ----------
396
        emoji: :class:`str`
397
            Character for emoji. Does not need to be URL encoded.
398
        """
399
400
        await self._http.delete(
401
            f"/channels/{self.channel_id}/messages/{self.id}/reactions/{emoji}/@me"
402
        )
403
404
    async def remove_user_reaction(self, emoji: str, user_id: Snowflake):
405
        """|coro|
406
407
        Deletes another user's reaction. Requires the ``MANAGE_MESSAGES``
408
        intent.
409
410
        Parameters
411
        ----------
412
        emoji: :class:`str`
413
            Character for emoji. Does not need to be URL encoded.
414
        user_id: :class:`~pincer.utils.snowflake.Snowflake`
415
            User ID
416
        """
417
418
        await self._http.delete(
419
            f"/channels/{self.channel_id}/messages/{self.id}/reactions/{emoji}"
420
            f"/{user_id}"
421
        )
422
423
    async def get_reactions(
424
        self, emoji: str, after: Snowflake = 0, limit=25
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
425
    ) -> Generator[User, None, None]:
426
        # TODO: HTTP Client will need to refactored to allow parameters using aiohttp's system.
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
427
        """|coro|
428
429
        Returns the users that reacted with this emoji.
430
431
        Parameters
432
        ----------
433
        emoji: :class:`str`
434
            Emoji to get users for.
435
        after: :class:`~pincer.utils.snowflake.Snowflake`
436
            Get users after this user ID. Returns all users if not provided.
437
            |default| ``0``
438
        limit: :class:`int`
439
            Max number of users to return (1-100).
440
            |default| ``25``
441
        """
442
443
        for user in await self._http.get(
444
            f"/channels/{self.channel_id}/messages/{self.id}/reactions/{emoji}"
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
445
            f"?after={after}&limit={limit}"
446
        ):
447
            yield User.from_dict(user)
448
449
    async def remove_all_reactions(self):
450
        """|coro|
451
452
        Delete all reactions on a message. Requires the ``MANAGE_MESSAGES``
453
        intent.
454
        """
455
456
        await self._http.delete(
457
            f"/channels/{self.channel_id}/messages/{self.id}/reactions"
458
        )
459
460
    async def remove_emoji(self, emoji):
461
        """|coro|
462
463
        Deletes all the reactions for a given emoji on a message. Requires the
464
        ``MANAGE_MESSAGES`` intent.
465
466
        Parameters
467
        ----------
468
        emoji: :class:`str`
469
            Character for emoji. Does not need to be URL encoded.
470
        """
471
472
        await self._http.delete(
473
            f"/channels/{self.channel_id}/messages/{self.id}/reactions/{emoji}"
474
        )
475
476
    # TODO: Implement file (https://discord.com/developers/docs/resources/channel#edit-message)
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
477
    async def edit(
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
478
        self,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
479
        content: str = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
480
        embeds: List[Embed] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
481
        flags: int = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
482
        allowed_mentions: AllowedMentions = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
483
        attachments: List[Attachment] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
484
        components: List[MessageComponent] = None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
485
    ):
486
        """|coro|
487
488
        Edit a previously sent message. The fields content, embeds, and flags
489
        can be edited by the original message author. Other users can only
490
        edit flags and only if they have the ``MANAGE_MESSAGES`` permission in
491
        the corresponding channel. When specifying flags, ensure to include
492
        all previously set flags/bits in addition to ones that you are
493
        modifying.
494
495
        Parameters
496
        ----------
497
        content: :class:`str`
498
            The message contents (up to 2000 characters)
499
            |default| ``None``
500
        embeds: List[:class:`~pincer.objects.message.embed.Embed`]
501
            Embedded rich content (up to 6000 characters)
502
        flags: :class:`int`
503
            Edit the flags of a message (only ``SUPPRESS_EMBEDS`` can
504
            currently be set/unset)
505
        allowed_mentions: :class:`~pincer.objects.message.message.AllowedMentions`
506
            allowed mentions for the message
507
        attachments: List[:class:`~pincer.objects.message.attachment.Attachment`]
508
            attached files to keep
509
        components: List[:class:`~pincer.objects.message.component.MessageComponent`]
510
            the components to include with the message
511
        """
512
513
        data = {}
514
515
        def set_if_not_none(value: Any, name: str):
516
            if isinstance(value, APIObject):
517
                data[name] = value.to_dict()
518
            elif value is not None:
519
                data[name] = value
520
521
        set_if_not_none(content, "content")
522
        set_if_not_none(embeds, "embeds")
523
        set_if_not_none(flags, "flags")
524
        set_if_not_none(allowed_mentions, "allowed_mentions")
525
        set_if_not_none(attachments, "attachments")
526
        set_if_not_none(components, "components")
527
528
        await self._http.patch(
529
            f"/channels/{self.channel_id}/messages/{self.id}",
530
            data=data
531
        )
532
533
    async def delete(self):
534
        """|coro|
535
536
        Delete a message. Requires the ``MANAGE_MESSAGES`` intent if the
537
        message was not sent by the current user.
538
        """
539
540
        await self._http.delete(
541
            f"/channels/{self.channel_id}/messages/{self.id}"
542
        )
543
544
    @property
545
    def clean_content(self):
546
        """
547
        The message content with any special characters removed.
548
        """
549
        new_content = self.content
550
        subs = [
551
                r"\*\*(.*?)\*\*",  # bold
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (remove 4 spaces).
Loading history...
552
                r"\*(.*?)\*",  # italic
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (remove 4 spaces).
Loading history...
553
                r"_(.*?)_",  # italic2
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (remove 4 spaces).
Loading history...
554
                r"\*\*\*(.*?)\*\*\*",  # bold+italic
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (remove 4 spaces).
Loading history...
555
                r"\_\_(.*?)\_\_",  # underline
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (remove 4 spaces).
Loading history...
556
                r"~~(.*?)~~",  # crossed
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (remove 4 spaces).
Loading history...
557
                r"`?`(.*?)`?`",  # small code blocks
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (remove 4 spaces).
Loading history...
558
                r"\|\|(.*?)\|\|"  # spoilers
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (remove 4 spaces).
Loading history...
559
        ]
560
        for i in subs:
561
            new_content = sub(i, r"\1", new_content)
562
        remove_code_blocks = sub(r"(.*?)```[a-zA-Z]+(\s*)+\n((?:.|\s)*?)```", r"\1\2\3", new_content)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (101/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
563
564
        return remove_code_blocks
565