Repository: hikari-py/hikari (2022-12-03 ~ 2024-01-21)

problem_statement: GuildThreadChannel.is_nsfw should be removed
This is just never supplied, a thread's nsfw state is implicitly inherited from the parent channel and never supplied on the thread object itself

Might also be worth refining this further, are we sure we can't just do `is_nsfw=data["nsfw"]` or `is_nsfw=data.get("nsfw", False)` for the channel models where its applicable and just leave it out for everything else
date: 2022-12-03
patch: diff --git a/changes/1386.bugfix.md b/changes/1386.bugfix.md
new file mode 100644
index 00000000..7f5f02a2
--- /dev/null
+++ b/changes/1386.bugfix.md
@@ -0,0 +1,3 @@
+Remove incorrect `is_nsfw` field from threads.
+- The "NSFW" status is inherited from the parent object and not sent for threads.
+- This also involved moving the base attribute from `GuildChannel` to `PermissibleGuildChannel`.


----

problem_statement: Option to only cache the bot member
## Summary

This requests aims to introduce a new option for enabling the members cache ONLY for the bot member.
Similar to `CacheComponents.ME` but for the member.

## Why is this needed?

The bot member is very useful for permissions calculations and enabling the members caches every member, increasing memory consumption and CPU consumption on startup.

## Ideal implementation

see pr :)

date: 2023-08-08
patch: diff --git a/changes/1679.feature.md b/changes/1679.feature.md
new file mode 100644
index 00000000..4e2839f5
--- /dev/null
+++ b/changes/1679.feature.md
@@ -0,0 +1 @@
+Add `CacheSettings.only_my_member` to only cache the bot member.


----

problem_statement: `Member.joined_at` is now nullable due to breaking API change
### Steps to reproduce

1. Invite guest via guest invite
2. Try deserializing the incoming events that contain the member (`VOICE_STATE_UPDATE` is definitely affected, unsure about the rest)
3. Bot explod


### Expected result

Bot not explod

### Actual result

Bot explod

```
TypeError: argument must be str
E 2024-01-20 01:05:35,693 asyncio: Exception occurred in raw event dispatch conduit
task: <Task pending name='dispatch VOICE_STATE_UPDATE' coro=<EventManagerBase._handle_dispatch() running at \hikari\impl\event_manager_base.py:609>>
Traceback (most recent call last):
  File "\hikari\impl\event_manager_base.py", line 602, in _handle_dispatch
    await consumer.callback(shard, payload)
  File "\hikari\impl\event_manager.py", line 810, in on_voice_state_update
    event = self._event_factory.deserialize_voice_state_update_event(shard, payload, old_state=old)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "\hikari\impl\event_factory.py", line 919, in deserialize_voice_state_update_event
    state = self._app.entity_factory.deserialize_voice_state(payload)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "\hikari\impl\entity_factory.py", line 3598, in deserialize_voice_state
    member = self.deserialize_member(payload["member"], guild_id=guild_id)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "\hikari\impl\entity_factory.py", line 1809, in deserialize_member
    joined_at = time.iso8601_datetime_string_to_datetime(payload["joined_at"])
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```

### Further info

The `joined_at` field is now nullable, according to this PR on the DAPI docs:

https://github.com/discord/discord-api-docs/pull/6247

This seems to only affect `VOICE_STATE_UPDATE` for now(?)

### Checklist

- [X] I have made sure to remove ANY sensitive information (bot token, passwords, credentials, personal details, etc.).
- [X] I have searched the issue tracker and have made sure it's not a duplicate. If it is a follow up of another issue, I have specified it.
date: 2024-01-21
patch: diff --git a/changes/1812.bugfix.md b/changes/1812.bugfix.md
new file mode 100644
index 00000000..504d10e7
--- /dev/null
+++ b/changes/1812.bugfix.md
@@ -0,0 +1,2 @@
+`Member.joined_at` is now nullable due to breaking API change
+ - This will be received on guest members with temporary membership
diff --git a/hikari/guilds.py b/hikari/guilds.py
index 599cab81..c570efe0 100644
--- a/hikari/guilds.py
+++ b/hikari/guilds.py
@@ -359,8 +359,12 @@ class Member(users.User):
     This will be `hikari.undefined.UNDEFINED` if it's state is unknown.
     """
 
-    joined_at: datetime.datetime = attrs.field(repr=True)
-    """The datetime of when this member joined the guild they belong to."""
+    joined_at: typing.Optional[datetime.datetime] = attrs.field(repr=True)
+    """The datetime of when this member joined the guild they belong to.
+
+    This will be `None` for guest members that have been temporarily
+    invited.
+    """
 
     nickname: typing.Optional[str] = attrs.field(repr=True)
     """This member's nickname.
diff --git a/hikari/impl/entity_factory.py b/hikari/impl/entity_factory.py
index a5f6cebf..507bdbb8 100644
--- a/hikari/impl/entity_factory.py
+++ b/hikari/impl/entity_factory.py
@@ -1806,7 +1806,8 @@ def deserialize_member(
         if guild_id not in role_ids:
             role_ids.append(guild_id)
 
-        joined_at = time.iso8601_datetime_string_to_datetime(payload["joined_at"])
+        raw_joined_at = payload["joined_at"]
+        joined_at = time.iso8601_datetime_string_to_datetime(raw_joined_at) if raw_joined_at is not None else None
 
         raw_premium_since = payload.get("premium_since")
         premium_since = (
diff --git a/hikari/internal/cache.py b/hikari/internal/cache.py
index 89a5ba15..37551264 100644
--- a/hikari/internal/cache.py
+++ b/hikari/internal/cache.py
@@ -410,7 +410,7 @@ class MemberData(BaseData[guilds.Member]):
     nickname: typing.Optional[str] = attrs.field()
     guild_avatar_hash: typing.Optional[str] = attrs.field()
     role_ids: typing.Tuple[snowflakes.Snowflake, ...] = attrs.field()
-    joined_at: datetime.datetime = attrs.field()
+    joined_at: typing.Optional[datetime.datetime] = attrs.field()
     premium_since: typing.Optional[datetime.datetime] = attrs.field()
     is_deaf: undefined.UndefinedOr[bool] = attrs.field()
     is_mute: undefined.UndefinedOr[bool] = attrs.field()

test_patch: diff --git a/tests/hikari/impl/test_entity_factory.py b/tests/hikari/impl/test_entity_factory.py
index 35d07ed1..6c29210e 100644
--- a/tests/hikari/impl/test_entity_factory.py
+++ b/tests/hikari/impl/test_entity_factory.py
@@ -3230,7 +3230,7 @@ def test_deserialize_member_with_null_fields(self, entity_factory_impl, user_pay
             {
                 "nick": None,
                 "roles": ["11111", "22222", "33333", "44444"],
-                "joined_at": "2015-04-26T06:26:56.936000+00:00",
+                "joined_at": None,
                 "premium_since": None,
                 "deaf": False,
                 "avatar": None,
@@ -3244,6 +3244,7 @@ def test_deserialize_member_with_null_fields(self, entity_factory_impl, user_pay
         assert member.nickname is None
         assert member.premium_since is None
         assert member.guild_avatar_hash is None
+        assert member.joined_at is None
         assert isinstance(member, guild_models.Member)
 
     def test_deserialize_member_with_undefined_fields(self, entity_factory_impl, user_payload):