Skip to content

Commit

Permalink
feat: switch to Self type for constructor method returns
Browse files Browse the repository at this point in the history
  • Loading branch information
linuxdaemon committed Apr 16, 2024
1 parent 0e4d935 commit 43749db
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 25 deletions.
51 changes: 26 additions & 25 deletions irclib/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,10 @@ def __str__(self) -> str:
return self.name

@classmethod
def parse(cls, text: str) -> "Cap":
def parse(cls, text: str) -> Self:
"""Parse a CAP entity from a string"""
name, _, value = text.partition(CAP_VALUE_SEP)
return Cap(name, value or None)
return cls(name, value or None)


class CapList(Parseable, List[Cap]):
Expand Down Expand Up @@ -161,7 +161,7 @@ def __str__(self) -> str:
return CAP_SEP.join(map(str, self))

@classmethod
def parse(cls, text: str) -> "CapList":
def parse(cls, text: str) -> Self:
"""Parse a list of CAPs from a string"""
if text.startswith(":"):
text = text[1:] # Remove leading colon
Expand All @@ -175,7 +175,7 @@ def parse(cls, text: str) -> "CapList":
[] if not text else (Cap.parse(s) for s in stripped.split(CAP_SEP))
)

return CapList(caps)
return cls(caps)


class MessageTag(Parseable):
Expand Down Expand Up @@ -259,7 +259,7 @@ def __ne__(self, other: object) -> bool:
return NotImplemented

@classmethod
def parse(cls, text: str) -> "MessageTag":
def parse(cls, text: str) -> Self:
"""
Parse a tag from a string
Expand All @@ -270,7 +270,7 @@ def parse(cls, text: str) -> "MessageTag":
if value:
value = MessageTag.unescape(value)

return MessageTag(name, value, has_value=bool(sep))
return cls(name, value, has_value=bool(sep))


class TagList(Parseable, Dict[str, MessageTag]):
Expand Down Expand Up @@ -316,21 +316,19 @@ def __ne__(self, other: object) -> bool:
return dict(self) != dict(obj)

@classmethod
def parse(cls, text: str) -> "TagList":
def parse(cls, text: str) -> Self:
"""
Parse the list of tags from a string
:param text: The string to parse
:return: The parsed object
"""
return TagList(
map(MessageTag.parse, filter(None, text.split(TAGS_SEP)))
)
return cls(map(MessageTag.parse, filter(None, text.split(TAGS_SEP))))

@staticmethod
def from_dict(tags: Dict[str, str]) -> "TagList":
@classmethod
def from_dict(cls, tags: Dict[str, str]) -> Self:
"""Create a TagList from a dict of tags"""
return TagList(MessageTag(k, v) for k, v in tags.items())
return cls(MessageTag(k, v) for k, v in tags.items())


class Prefix(Parseable):
Expand Down Expand Up @@ -414,15 +412,15 @@ def __ne__(self, other: object) -> bool:
return NotImplemented

@classmethod
def parse(cls, text: str) -> "Prefix":
def parse(cls, text: str) -> Self:
"""
Parse the prefix from a string
:param text: String to parse
:return: Parsed Object
"""
if not text:
return Prefix()
return cls()

match = PREFIX_RE.match(text)
if not match: # pragma: no cover
Expand All @@ -431,7 +429,7 @@ def parse(cls, text: str) -> "Prefix":
raise ParseError(msg)

nick, user, host = match.groups()
return Prefix(nick, user, host)
return cls(nick, user, host)


class ParamList(Parseable, List[str]):
Expand Down Expand Up @@ -481,11 +479,11 @@ def __ne__(self, other: object) -> bool:

return NotImplemented

@staticmethod
def from_list(data: Sequence[str]) -> "ParamList":
@classmethod
def from_list(cls, data: Sequence[str]) -> Self:
"""Create a ParamList from a Sequence of strings."""
if not data:
return ParamList()
return cls()

args = list(data[:-1])
if data[-1].startswith(TRAIL_SENTINEL) or not data[-1]:
Expand All @@ -495,10 +493,10 @@ def from_list(data: Sequence[str]) -> "ParamList":
has_trail = False
args.append(data[-1])

return ParamList(*args, has_trail=has_trail)
return cls(*args, has_trail=has_trail)

@classmethod
def parse(cls, text: str) -> "ParamList":
def parse(cls, text: str) -> Self:
"""
Parse a list of parameters
Expand All @@ -517,7 +515,7 @@ def parse(cls, text: str) -> "ParamList":
if arg:
args.append(arg)

return ParamList(*args, has_trail=has_trail)
return cls(*args, has_trail=has_trail)


def _parse_tags(
Expand Down Expand Up @@ -639,9 +637,12 @@ def __ne__(self, other: object) -> bool:
return NotImplemented

@classmethod
def parse(cls, text: Union[str, bytes]) -> "Message":
def parse(cls, text: Union[str, bytes]) -> Self:
"""Parse an IRC message in to objects"""
if isinstance(text, bytes):
if isinstance(text, memoryview):
text = text.tobytes().decode(errors="ignore")

if isinstance(text, (bytes, bytearray)):
text = text.decode(errors="ignore")

tags = ""
Expand All @@ -659,4 +660,4 @@ def parse(cls, text: Union[str, bytes]) -> "Message":
prefix_obj = Prefix.parse(prefix[1:]) if prefix else None
command = command.upper()
param_obj = ParamList.parse(params)
return Message(tags_obj, prefix_obj, command, param_obj)
return cls(tags_obj, prefix_obj, command, param_obj)
12 changes: 12 additions & 0 deletions tests/parser_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,18 @@ def test_parse_bytes(self) -> None:
assert line.command == "COMMAND"
assert line.parameters == ["some", "params", "and stuff"]

def test_parse_bytearray(self) -> None:
"""Test parsing bytearray"""
line = Message.parse(bytearray(b"COMMAND some params :and stuff"))
assert line.command == "COMMAND"
assert line.parameters == ["some", "params", "and stuff"]

def test_parse_memoryview(self) -> None:
"""Test parsing memoryview"""
line = Message.parse(memoryview(b"COMMAND some params :and stuff"))
assert line.command == "COMMAND"
assert line.parameters == ["some", "params", "and stuff"]

@pytest.mark.parametrize(
("obj", "text"),
[
Expand Down

0 comments on commit 43749db

Please sign in to comment.