Repository: hikari-py/hikari
Pull request #411 (2020-12-23 02:14:50)

Make applications.TeamMember extend users.User plus chunk changes

### Summary
* request presences when chunking on guild create if possible
* Make applications.TeamMember extend users.User

### 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.

### Related issues
<!--
To mention an issue use `#issue-id` and to mention a merge request use `!merge-request-id`
To close/fix an issue use `Close #issue-id` or `Fix #issue-id` (depending on the merge request)
-->


FasterSpeeding: > Could you please add integration tests for this too? I believe they will fail as you need to implement **eq** (check guilds.Member for more info 👍)

The equality override and integration tests is already there, this pr just adds in delegation. 
davfsa: Oh, didnt see that 😅 

Patch:
diff --git a/hikari/applications.py b/hikari/applications.py
index f470a813..598ac7e7 100644
--- a/hikari/applications.py
+++ b/hikari/applications.py
@@ -42,14 +42,15 @@
 from hikari import guilds
 from hikari import snowflakes
 from hikari import urls
+from hikari import users
 from hikari.internal import attr_extensions
 from hikari.internal import enums
 from hikari.internal import routes
 
 if typing.TYPE_CHECKING:
+    from hikari import channels
     from hikari import permissions as permissions_
     from hikari import traits
-    from hikari import users
 
 
 @typing.final
@@ -258,12 +259,9 @@ class TeamMembershipState(int, enums.Enum):
 
 @attr_extensions.with_copy
 @attr.s(eq=False, hash=False, init=True, kw_only=True, slots=True, weakref_slot=False)
-class TeamMember:
+class TeamMember(users.User):
     """Represents a member of a Team."""
 
-    app: traits.RESTAware = attr.ib(repr=False, metadata={attr_extensions.SKIP_DEEP_COPY: True})
-    """The client application that models may use for procedures."""
-
     membership_state: typing.Union[TeamMembershipState, int] = attr.ib(repr=False)
     """The state of this user's membership."""
 
@@ -280,6 +278,58 @@ class TeamMember:
     user: users.User = attr.ib(repr=True)
     """The user representation of this team member."""
 
+    @property
+    def app(self) -> traits.RESTAware:
+        """Return the app that is bound to the user object."""
+        return self.user.app
+
+    @property
+    def avatar_hash(self) -> typing.Optional[str]:
+        return self.user.avatar_hash
+
+    @property
+    def avatar_url(self) -> typing.Optional[files.URL]:
+        return self.user.avatar_url
+
+    @property
+    def default_avatar_url(self) -> files.URL:
+        return self.user.default_avatar_url
+
+    @property
+    def discriminator(self) -> str:
+        return self.user.discriminator
+
+    @property
+    def flags(self) -> users.UserFlag:
+        return self.user.flags
+
+    @property
+    def id(self) -> snowflakes.Snowflake:
+        return self.user.id
+
+    @id.setter
+    def id(self, value: snowflakes.Snowflake) -> None:
+        raise TypeError("Cannot mutate the ID of a member")
+
+    @property
+    def is_bot(self) -> bool:
+        return self.user.is_bot
+
+    @property
+    def is_system(self) -> bool:
+        return self.user.is_system
+
+    @property
+    def mention(self) -> str:
+        return self.user.mention
+
+    @property
+    def username(self) -> str:
+        return self.user.username
+
+    async def fetch_dm_channel(self) -> channels.DMChannel:
+        return await self.user.fetch_dm_channel()
+
     def __str__(self) -> str:
         return str(self.user)
 
diff --git a/hikari/impl/entity_factory.py b/hikari/impl/entity_factory.py
index 9abf38db..0339d601 100644
--- a/hikari/impl/entity_factory.py
+++ b/hikari/impl/entity_factory.py
@@ -271,7 +271,6 @@ def deserialize_application(self, payload: data_binding.JSONObject) -> applicati
             members = {}
             for member_payload in team_payload["members"]:
                 team_member = application_models.TeamMember(
-                    app=self._app,
                     membership_state=application_models.TeamMembershipState(member_payload["membership_state"]),
                     permissions=member_payload["permissions"],
                     team_id=snowflakes.Snowflake(member_payload["team_id"]),
diff --git a/hikari/impl/stateful_event_manager.py b/hikari/impl/stateful_event_manager.py
index 54322bc2..f88defc8 100644
--- a/hikari/impl/stateful_event_manager.py
+++ b/hikari/impl/stateful_event_manager.py
@@ -151,7 +151,7 @@ async def on_guild_create(self, shard: gateway_shard.GatewayShard, payload: data
         # to chunk small guilds.
         if (event.guild.is_large or not presences_declared) and members_declared:
             # We create a task here instead of awaiting the result to avoid any rate-limits from delaying dispatch.
-            coroutine = shard.request_guild_members(event.guild)
+            coroutine = shard.request_guild_members(event.guild, include_presences=bool(presences_declared))
             asyncio.create_task(coroutine, name=f"{event.shard.id}:{event.guild.id} guild create members request")
 
         await self.dispatch(event)


Test patch:
diff --git a/tests/hikari/integration/test_users_comparison.py b/tests/hikari/integration/test_users_comparison.py
index 341d85aa..31550de2 100644
--- a/tests/hikari/integration/test_users_comparison.py
+++ b/tests/hikari/integration/test_users_comparison.py
@@ -59,7 +59,6 @@ def make_user(user_id, username):
 def make_team_member(user_id, username):
     user = make_user(user_id, username)
     return applications.TeamMember(
-        app=user.app,
         membership_state=applications.TeamMembershipState.ACCEPTED,
         permissions="*",
         team_id=snowflakes.Snowflake(1234),
diff --git a/tests/hikari/test_applications.py b/tests/hikari/test_applications.py
index 3f094674..dcf00d60 100644
--- a/tests/hikari/test_applications.py
+++ b/tests/hikari/test_applications.py
@@ -28,31 +28,79 @@
 from tests.hikari import hikari_test_helpers
 
 
-def test_OAuth2Scope_str_operator():
-    scope = applications.OAuth2Scope("activities.read")
-    assert str(scope) == "ACTIVITIES_READ"
+class TestOAuth2Scope:
+    def test_str_operator(self):
+        scope = applications.OAuth2Scope("activities.read")
+        assert str(scope) == "ACTIVITIES_READ"
 
 
-def test_ConnectionVisibility_str_operator():
-    connection_visibility = applications.ConnectionVisibility(1)
-    assert str(connection_visibility) == "EVERYONE"
+class TestConnectionVisibility:
+    def test_str_operator(self):
+        connection_visibility = applications.ConnectionVisibility(1)
+        assert str(connection_visibility) == "EVERYONE"
 
 
-def test_TeamMembershipState_str_operator():
-    state = applications.TeamMembershipState(2)
-    assert str(state) == "ACCEPTED"
+class TestTeamMembershipState:
+    def test_str_operator(self):
+        state = applications.TeamMembershipState(2)
+        assert str(state) == "ACCEPTED"
 
 
-def test_TeamMember_str_operator():
-    mock_team_member = mock.Mock(
-        applications.TeamMember, user=mock.Mock(users.User, __str__=mock.Mock(return_value="mario#1234"))
-    )
-    assert applications.TeamMember.__str__(mock_team_member) == "mario#1234"
+class TestTeamMember:
+    @pytest.fixture()
+    def model(self):
+        return applications.TeamMember(membership_state=4, permissions=["*"], team_id=34123, user=mock.Mock(users.User))
+
+    def test_app_property(self, model):
+        assert model.app is model.user.app
+
+    def test_avatar_hash_property(self, model):
+        assert model.avatar_hash is model.user.avatar_hash
+
+    def test_avatar_url_property(self, model):
+        assert model.avatar_url is model.user.avatar_url
+
+    def test_default_avatar_url_property(self, model):
+        assert model.default_avatar_url is model.user.default_avatar_url
+
+    def test_discriminator_property(self, model):
+        assert model.discriminator is model.user.discriminator
+
+    def test_flags_property(self, model):
+        assert model.flags is model.user.flags
+
+    def test_id_property(self, model):
+        assert model.id is model.user.id
 
+    def test_id_setter(self, model):
+        with pytest.raises(TypeError, match="Cannot mutate the ID of a member"):
+            model.id = 42
 
-def test_Team_str_operator():
-    team = applications.Team(id=696969, app=object(), icon_hash="", members=[], owner_id=0)
-    assert str(team) == "Team 696969"
+    def test_is_bot_property(self, model):
+        assert model.is_bot is model.user.is_bot
+
+    def test_is_system_property(self, model):
+        assert model.is_system is model.user.is_system
+
+    def test_mention_property(self, model):
+        assert model.app is model.user.app
+
+    def test_username_property(self, model):
+        assert model.app is model.user.app
+
+    @pytest.mark.asyncio
+    async def test_fetch_dm_channel(self, model):
+        model.user.fetch_dm_channel = mock.AsyncMock()
+
+        result = await model.fetch_dm_channel()
+        assert result is model.user.fetch_dm_channel.return_value
+        model.user.fetch_dm_channel.assert_awaited_once()
+
+    def test_str_operator(self):
+        mock_team_member = mock.Mock(
+            applications.TeamMember, user=mock.Mock(users.User, __str__=mock.Mock(return_value="mario#1234"))
+        )
+        assert applications.TeamMember.__str__(mock_team_member) == "mario#1234"
 
 
 class TestTeam:
@@ -62,6 +110,10 @@ def model(self):
             applications.Team, slots_=False, init_=False, id=123, icon_hash="ahashicon"
         )()
 
+    def test_str_operator(self):
+        team = applications.Team(id=696969, app=object(), icon_hash="", members=[], owner_id=0)
+        assert str(team) == "Team 696969"
+
     def test_icon_url_property(self, model):
         model.format_icon = mock.Mock(return_value="url")