Repository: hikari-py/hikari
Pull request #622 (2021-05-27 06:24:36)

Replace Guild.is_nsfw with Guild.nsfw_level
### Checklist
<!-- Make sure to tick all the following boxes by putting an `x` in between (like this `[x]`) -->
- [x] I have run `nox` and all the pipelines have passed.
- [x] I have made unittests according to the code I have added/modified/deleted.

*Note: Even tho this is marked as breaking, this is just because it will break any bot pulling from master. `is_nsfw` never got to be deployed in a proper version of the lib*

davfsa: @FasterSpeeding Changed all the docstring to try and make them clearer

Patch:
diff --git a/hikari/guilds.py b/hikari/guilds.py
index 44506cf3..ca3f1349 100644
--- a/hikari/guilds.py
+++ b/hikari/guilds.py
@@ -40,6 +40,7 @@
     "GuildPremiumTier",
     "GuildPreview",
     "GuildMemberBan",
+    "GuildNSFWLevel",
     "Member",
     "Integration",
     "IntegrationAccount",
@@ -246,6 +247,23 @@ class GuildVerificationLevel(int, enums.Enum):
     """Must have a verified phone number."""
 
 
+@typing.final
+class GuildNSFWLevel(int, enums.Enum):
+    """Represents the NSFW level of a guild."""
+
+    DEFAULT = 0
+    """Guild has not been categorized yet."""
+
+    EXPLICIT = 1
+    """Guild contains explicit NSFW content."""
+
+    SAFE = 2
+    """Guild is safe of NSFW content."""
+
+    AGE_RESTRICTED = 3
+    """Guild may contain NSFW content."""
+
+
 @attr_extensions.with_copy
 @attr.define(hash=False, kw_only=True, weakref_slot=False)
 class GuildWidget:
@@ -1189,8 +1207,8 @@ class Guild(PartialGuild, abc.ABC):
     this will be `builtins.None`.
     """
 
-    is_nsfw: bool = attr.field(eq=False, hash=False, repr=False)
-    """Whether the guild is designated as NSFW."""
+    nsfw_level: GuildNSFWLevel = attr.field(eq=False, hash=False, repr=False)
+    """The NSFW level of the guild."""
 
     @property
     def banner_url(self) -> typing.Optional[files.URL]:
diff --git a/hikari/impl/entity_factory.py b/hikari/impl/entity_factory.py
index d1828b0d..5d2c6404 100644
--- a/hikari/impl/entity_factory.py
+++ b/hikari/impl/entity_factory.py
@@ -136,7 +136,7 @@ class _GuildFields:
     premium_subscription_count: typing.Optional[int] = attr.field()
     preferred_locale: str = attr.field()
     public_updates_channel_id: typing.Optional[snowflakes.Snowflake] = attr.field()
-    is_nsfw: bool = attr.field()
+    nsfw_level: guild_models.GuildNSFWLevel = attr.field()
 
 
 @attr_extensions.with_copy
@@ -1337,7 +1337,7 @@ def _set_guild_attributes(self, payload: data_binding.JSONObject) -> _GuildField
             premium_subscription_count=payload.get("premium_subscription_count"),
             preferred_locale=payload["preferred_locale"],
             public_updates_channel_id=public_updates_channel_id,
-            is_nsfw=payload["nsfw"],
+            nsfw_level=guild_models.GuildNSFWLevel(payload["nsfw_level"]),
         )
 
     def deserialize_rest_guild(self, payload: data_binding.JSONObject) -> guild_models.RESTGuild:
@@ -1367,7 +1367,7 @@ def deserialize_rest_guild(self, payload: data_binding.JSONObject) -> guild_mode
             snowflakes.Snowflake(emoji["id"]): self.deserialize_known_custom_emoji(emoji, guild_id=guild_fields.id)
             for emoji in payload["emojis"]
         }
-        guild = guild_models.RESTGuild(
+        return guild_models.RESTGuild(
             app=self._app,
             id=guild_fields.id,
             name=guild_fields.name,
@@ -1395,7 +1395,7 @@ def deserialize_rest_guild(self, payload: data_binding.JSONObject) -> guild_mode
             description=guild_fields.description,
             banner_hash=guild_fields.banner_hash,
             premium_tier=guild_fields.premium_tier,
-            is_nsfw=guild_fields.is_nsfw,
+            nsfw_level=guild_fields.nsfw_level,
             premium_subscription_count=guild_fields.premium_subscription_count,
             preferred_locale=guild_fields.preferred_locale,
             public_updates_channel_id=guild_fields.public_updates_channel_id,
@@ -1404,7 +1404,6 @@ def deserialize_rest_guild(self, payload: data_binding.JSONObject) -> guild_mode
             roles=roles,
             emojis=emojis,
         )
-        return guild
 
     def deserialize_gateway_guild(self, payload: data_binding.JSONObject) -> entity_factory.GatewayGuildDefinition:
         guild_fields = self._set_guild_attributes(payload)
@@ -1441,7 +1440,7 @@ def deserialize_gateway_guild(self, payload: data_binding.JSONObject) -> entity_
             premium_subscription_count=guild_fields.premium_subscription_count,
             preferred_locale=guild_fields.preferred_locale,
             public_updates_channel_id=guild_fields.public_updates_channel_id,
-            is_nsfw=guild_fields.is_nsfw,
+            nsfw_level=guild_fields.nsfw_level,
             is_large=is_large,
             joined_at=joined_at,
             member_count=member_count,
@@ -1524,7 +1523,7 @@ def _set_invite_attributes(self, payload: data_binding.JSONObject) -> _InviteFie
                 verification_level=guild_models.GuildVerificationLevel(guild_payload["verification_level"]),
                 vanity_url_code=guild_payload["vanity_url_code"],
                 welcome_screen=self.deserialize_welcome_screen(raw_welcome_screen) if raw_welcome_screen else None,
-                is_nsfw=guild_payload.get("nsfw"),
+                nsfw_level=guild_models.GuildNSFWLevel(guild_payload["nsfw_level"]),
             )
             guild_id = guild.id
         elif "guild_id" in payload:
diff --git a/hikari/invites.py b/hikari/invites.py
index dcb0cef6..f9123d38 100644
--- a/hikari/invites.py
+++ b/hikari/invites.py
@@ -136,11 +136,8 @@ class InviteGuild(guilds.PartialGuild):
     welcome_screen: typing.Optional[guilds.WelcomeScreen] = attr.field(eq=False, hash=False, repr=False)
     """The welcome screen of a community guild shown to new members, if set."""
 
-    is_nsfw: typing.Optional[bool] = attr.field(eq=False, hash=False, repr=False)
-    """Whether the guild is designated as NSFW.
-
-    This field is currently only returned by the GET Invite REST endpoint.
-    """
+    nsfw_level: guilds.GuildNSFWLevel = attr.field(eq=False, hash=False, repr=False)
+    """The NSFW level of the guild."""
 
     @property
     def splash_url(self) -> typing.Optional[files.URL]:


Test patch:
diff --git a/tests/hikari/impl/test_entity_factory.py b/tests/hikari/impl/test_entity_factory.py
index df2bcc49..8bc132e2 100644
--- a/tests/hikari/impl/test_entity_factory.py
+++ b/tests/hikari/impl/test_entity_factory.py
@@ -2198,7 +2198,7 @@ def deserialize_rest_guild_payload(
             "verification_level": 4,
             "widget_channel_id": "9439394949",
             "widget_enabled": True,
-            "nsfw": True,
+            "nsfw_level": 0,
         }
 
     def test_deserialize_rest_guild(
@@ -2257,7 +2257,7 @@ def test_deserialize_rest_guild(
         assert guild.public_updates_channel_id == 33333333
         assert guild.approximate_member_count == 15
         assert guild.approximate_active_member_count == 7
-        assert guild.is_nsfw is True
+        assert guild.nsfw_level == guild_models.GuildNSFWLevel.DEFAULT
 
     def test_deserialize_rest_guild_with_unset_fields(self, entity_factory_impl):
         guild = entity_factory_impl.deserialize_rest_guild(
@@ -2275,7 +2275,7 @@ def test_deserialize_rest_guild_with_unset_fields(self, entity_factory_impl):
                 "icon": "1a2b3c4d",
                 "id": "265828729970753537",
                 "mfa_level": 1,
-                "nsfw": True,
+                "nsfw_level": 0,
                 "name": "L33t guild",
                 "owner_id": "6969696",
                 "preferred_locale": "en-GB",
@@ -2322,7 +2322,7 @@ def test_deserialize_rest_guild_with_null_fields(self, entity_factory_impl):
                 "max_presences": None,
                 "max_video_channel_users": 25,
                 "mfa_level": 1,
-                "nsfw": False,
+                "nsfw_level": 0,
                 "name": "L33t guild",
                 "owner_id": "6969696",
                 "preferred_locale": "en-GB",
@@ -2410,7 +2410,7 @@ def deserialize_gateway_guild_payload(
             "voice_states": [voice_state_payload],
             "widget_channel_id": "9439394949",
             "widget_enabled": True,
-            "nsfw": False,
+            "nsfw_level": 0,
         }
 
     def test_deserialize_gateway_guild(
@@ -2465,7 +2465,7 @@ def test_deserialize_gateway_guild(
         assert guild.premium_subscription_count == 1
         assert guild.preferred_locale == "en-GB"
         assert guild.public_updates_channel_id == 33333333
-        assert guild.is_nsfw is False
+        assert guild.nsfw_level == guild_models.GuildNSFWLevel.DEFAULT
 
         assert guild_definition.roles == {
             41771983423143936: entity_factory_impl.deserialize_role(
@@ -2537,7 +2537,7 @@ def test_deserialize_gateway_guild_with_unset_fields(self, entity_factory_impl):
                 "system_channel_id": "19216801",
                 "vanity_url_code": "loool",
                 "verification_level": 4,
-                "nsfw": True,
+                "nsfw_level": 0,
             }
         )
         guild = guild_definition.guild
@@ -2598,7 +2598,7 @@ def test_deserialize_gateway_guild_with_null_fields(self, entity_factory_impl):
                 "voice_states": [],
                 "widget_channel_id": None,
                 "widget_enabled": True,
-                "nsfw": False,
+                "nsfw_level": 0,
             }
         )
         guild = guild_definition.guild
@@ -2660,7 +2660,7 @@ def invite_payload(
                 "verification_level": 2,
                 "vanity_url_code": "I-am-very-vain",
                 "welcome_screen": guild_welcome_screen_payload,
-                "nsfw": False,
+                "nsfw_level": 1,
             },
             "channel": partial_channel_payload,
             "inviter": user_payload,
@@ -2697,7 +2697,7 @@ def test_deserialize_invite(
         assert invite.guild.welcome_screen == entity_factory_impl.deserialize_welcome_screen(
             guild_welcome_screen_payload
         )
-        assert invite.guild.is_nsfw is False
+        assert invite.guild.nsfw_level == guild_models.GuildNSFWLevel.EXPLICIT
 
         assert invite.guild_id == 56188492224814744
         assert invite.channel == entity_factory_impl.deserialize_partial_channel(partial_channel_payload)
@@ -2712,12 +2712,10 @@ def test_deserialize_invite(
 
     def test_deserialize_invite_with_unset_guild_fields(self, entity_factory_impl, invite_payload):
         del invite_payload["guild"]["welcome_screen"]
-        del invite_payload["guild"]["nsfw"]
 
         invite = entity_factory_impl.deserialize_invite(invite_payload)
 
         assert invite.guild.welcome_screen is None
-        assert invite.guild.is_nsfw is None
 
     def test_deserialize_invite_with_null_fields(self, entity_factory_impl, partial_channel_payload):
         invite = entity_factory_impl.deserialize_invite(
@@ -2772,7 +2770,7 @@ def invite_with_metadata_payload(
                 "verification_level": 2,
                 "vanity_url_code": "I-am-very-vain",
                 "welcome_screen": guild_welcome_screen_payload,
-                "nsfw": True,
+                "nsfw_level": 0,
             },
             "channel": partial_channel_payload,
             "inviter": user_payload,
@@ -2813,7 +2811,7 @@ def test_deserialize_invite_with_metadata(
         assert invite_with_metadata.guild.welcome_screen == entity_factory_impl.deserialize_welcome_screen(
             guild_welcome_screen_payload
         )
-        assert invite_with_metadata.guild.is_nsfw is True
+        assert invite_with_metadata.guild.nsfw_level == guild_models.GuildNSFWLevel.DEFAULT
 
         assert invite_with_metadata.channel == entity_factory_impl.deserialize_partial_channel(partial_channel_payload)
         assert invite_with_metadata.inviter == entity_factory_impl.deserialize_user(user_payload)
@@ -2861,11 +2859,9 @@ def test_deserialize_invite_with_metadata_with_null_guild_fields(
         self, entity_factory_impl, invite_with_metadata_payload
     ):
         del invite_with_metadata_payload["guild"]["welcome_screen"]
-        del invite_with_metadata_payload["guild"]["nsfw"]
 
         invite = entity_factory_impl.deserialize_invite_with_metadata(invite_with_metadata_payload)
         assert invite.guild.welcome_screen is None
-        assert invite.guild.is_nsfw is None
 
     def test_max_age_when_zero(self, entity_factory_impl, invite_with_metadata_payload):
         invite_with_metadata_payload["max_age"] = 0
diff --git a/tests/hikari/test_guilds.py b/tests/hikari/test_guilds.py
index e179cad1..47c630c3 100644
--- a/tests/hikari/test_guilds.py
+++ b/tests/hikari/test_guilds.py
@@ -452,7 +452,6 @@ class TestGuild:
     def model(self, mock_app):
         return hikari_test_helpers.mock_class_namespace(guilds.Guild)(
             app=mock_app,
-            is_nsfw=False,
             id=snowflakes.Snowflake(123),
             splash_hash="splash_hash",
             discovery_splash_hash="discovery_splash_hash",
@@ -469,6 +468,7 @@ def model(self, mock_app):
             is_widget_enabled=False,
             max_video_channel_users=10,
             mfa_level=guilds.GuildMFALevel.NONE,
+            nsfw_level=guilds.GuildNSFWLevel.AGE_RESTRICTED,
             owner_id=snowflakes.Snowflake(1111),
             preferred_locale="en-GB",
             premium_subscription_count=12,
@@ -583,7 +583,6 @@ def model(self, mock_app):
             owner_id=snowflakes.Snowflake(1111),
             preferred_locale="en-GB",
             premium_subscription_count=12,
-            is_nsfw=True,
             premium_tier=guilds.GuildPremiumTier.TIER_3,
             public_updates_channel_id=None,
             rules_channel_id=None,
@@ -598,6 +597,7 @@ def model(self, mock_app):
             approximate_member_count=100,
             max_presences=100,
             max_members=100,
+            nsfw_level=guilds.GuildNSFWLevel.AGE_RESTRICTED,
         )
 
     def test_get_emoji(self, model):
@@ -618,7 +618,6 @@ class TestGatewayGuild:
     def model(self, mock_app):
         return guilds.GatewayGuild(
             app=mock_app,
-            is_nsfw=True,
             id=snowflakes.Snowflake(123),
             splash_hash="splash_hash",
             discovery_splash_hash="discovery_splash_hash",
@@ -649,6 +648,7 @@ def model(self, mock_app):
             is_large=True,
             joined_at=None,
             member_count=1,
+            nsfw_level=guilds.GuildNSFWLevel.AGE_RESTRICTED,
         )
 
     def test_channels(self, model):