Skip to content

[BUG] handle_user_input: wrong dict keys #12

Description

@o-murphy

Also I found strange definition and usage of this classes (ChatMode, Public, Channel, PrivateDM)
You are using it for chat mode checking over the isinstance, but it still not safe and not guarantee the instance will have an expected attributes. So it should be refactored.

In section

ChatMode is not an enum and also it have not attributes like Public/Channel/PrivateDM

It will raise AttributeError

if line == "/clear":
    clear_screen()
    print_banner()
    mode_name = {
        ChatMode.Public: "public chat",
        ChatMode.Channel: f"channel {self.chat_context.current_mode.name}",
        ChatMode.PrivateDM: f"DM with {self.chat_context.current_mode.nickname}",
    }.get(type(self.chat_context.current_mode), "unknown")
    print(f"» Cleared {mode_name}")
    print("> ", end="", flush=True)
    return

I propose you to refactor it into way like bellow, it should be more type safe

  • Declare ChatMode(Enum)

  • rename ChatMode to Chat should contain all possible fields for different chat modes

  • check chat mode over simple checking of .current_mode.mode which is ChatMode instead of isinstance statement

  • with this approach mode_name = {ChatMode.Public: ...} will work as expected

  • ChatContextcan be dataclass

  • [OPTIONAL] Public/Channel/PrivateDM should be a factory functions instead of classes

class ChatMode(Enum):
    Public = auto()
    Channel = auto()
    PrivateDM = auto()

@dataclass
class Chat:
    mode: ChatMode
    channame: Optional[str] = None
    nickname: Optional[str] = None  # maybe use single `.name` attr for both nickname and channame
    peer_id: Optional[str] = None

@dataclass
class ChatContext:
    current_chat: Chat = field(default=ChatMode.Public)
    active_channels: List[str] = field(default_factory=list)
    active_dms: Dict[str, str] = field(default_factory=dict)  # nickname -> peer_id
    last_private_sender: Optional[Tuple[str, str]] = None

# refactoring of format_prompt

FORMAT_PROMPT: Dict[ChatMode, str] = {
    ChatMode.Public: "[Public]",
    ChatMode.Channel: "[Channel]",
    ChatMode.PrivateDM: "[DM]",
}


def format_prompt(self) -> str:
    return FORMAT_PROMPT.get(self.current_chat.mode, "[UNKNOWN]")

def switch_to_number(self, num: int) -> bool:
    if num == 1:
        self.current_mode = Chat()  # Public by default
    ...
  
    if 1 < num <= channel_end:
        channel_idx = num - 2
        if channel_idx < len(self.active_channels):
            channel = self.active_channels[channel_idx]
            self.current_chat = Chat(ChatMode.Channel, channame=channel)
    ...
    if dm_idx < len(dm_list):
        nick, peer_id = dm_list[dm_idx]
        self.current_chat = Chat(ChatMode.PrivateDM, nickname=nick, peer_id=peer_id)

example of Chat factory methods

@dataclass
class Chat:
    mode: ChatMode
    channame: Optional[str] = None
    nickname: Optional[str] = None  # maybe use single `.name` attr for both nickname and channame
    peer_id: Optional[str] = None

@classmethod
def pub(cls):
    return cls(ChatMode.Public)

@classmethod
def chan(cls, channame):
    return cls(ChatMode.Channel, channame=channel)

@classmethod
def private(cls, nickname, peer_id):
    return cls(ChatMode.PrivateDM, nickname=nickname, peer_id=peer_id)

# to switch use like
if <condition>:
    self.current_chat = Chat.pub()
    self.current_chat = Chat.chan(channel)
    self.current_chat  = Chat.private(nick, peer_id)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions