Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autoformat all code with isort and black #6

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions irctokens/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from .line import Line, build, tokenise
from .hostmask import Hostmask, hostmask
from .line import Line, build, tokenise
from .stateful import StatefulDecoder, StatefulEncoder

4 changes: 2 additions & 2 deletions irctokens/const.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
TAG_UNESCAPED = ["\\", " ", ";", "\r", "\n"]
TAG_ESCAPED = ["\\\\", "\\s", "\\:", "\\r", "\\n"]
TAG_UNESCAPED = ["\\", " ", ";", "\r", "\n"]
TAG_ESCAPED = ["\\\\", "\\s", "\\:", "\\r", "\\n"]
16 changes: 9 additions & 7 deletions irctokens/formatting.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
from typing import Dict, List, Optional

from .const import TAG_ESCAPED, TAG_UNESCAPED


def _escape_tag(value: str):
for i, char in enumerate(TAG_UNESCAPED):
value = value.replace(char, TAG_ESCAPED[i])
return value


def format(
tags: Optional[Dict[str, str]],
source: Optional[str],
command: str,
params: List[str]):
tags: Optional[Dict[str, str]],
source: Optional[str],
command: str,
params: List[str],
):
outs: List[str] = []
if tags:
tags_str = []
Expand All @@ -36,9 +40,7 @@ def format(
raise ValueError("non last params cannot start with colon")
outs.extend(params)

if (not last or
" " in last or
last.startswith(":")):
if not last or " " in last or last.startswith(":"):
last = f":{last}"
outs.append(last)
return " ".join(outs)
21 changes: 12 additions & 9 deletions irctokens/hostmask.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
from typing import Optional


class Hostmask(object):
def __init__(self, source: str,
nickname: str,
username: Optional[str],
hostname: Optional[str]):
def __init__(
self,
source: str,
nickname: str,
username: Optional[str],
hostname: Optional[str],
):
self._source = source
self.nickname = nickname
self.username = username
self.hostname = hostname

def __str__(self) -> str:
return self._source

def __repr__(self) -> str:
return f"Hostmask({self._source})"

def __eq__(self, other) -> bool:
if isinstance(other, Hostmask):
return str(self) == str(other)
else:
return False


def hostmask(source: str) -> Hostmask:
username, _, hostname = source.partition("@")
nickname, _, username = username.partition("!")
return Hostmask(
source,
nickname,
username or None,
hostname or None)
return Hostmask(source, nickname, username or None, hostname or None)
61 changes: 36 additions & 25 deletions irctokens/line.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
from typing import Dict, List, Optional, Union
from .const import TAG_ESCAPED, TAG_UNESCAPED
from .hostmask import Hostmask, hostmask
from typing import Dict, List, Optional, Union

from .const import TAG_ESCAPED, TAG_UNESCAPED
from .formatting import format as format_
from .hostmask import Hostmask, hostmask


class Line(object):
def __init__(self,
tags: Optional[Dict[str, str]],
source: Optional[str],
command: str,
params: List[str]):
self.tags = tags
self.source = source
def __init__(
self,
tags: Optional[Dict[str, str]],
source: Optional[str],
command: str,
params: List[str],
):
self.tags = tags
self.source = source
self.command = command
self.params = params
self.params = params

def __eq__(self, other) -> bool:
if isinstance(other, Line):
return self.format() == other.format()
else:
return False

def __repr__(self) -> str:
return (f"Line(tag={self.tags!r}, source={self.source!r}"
f", command={self.command!r}, params={self.params!r})")
return (
f"Line(tag={self.tags!r}, source={self.source!r}"
f", command={self.command!r}, params={self.params!r})"
)

_hostmask: Optional[Hostmask] = None

@property
def hostmask(self) -> Hostmask:
if self.source is not None:
Expand All @@ -38,25 +46,28 @@ def format(self) -> str:

def with_source(self, source: str) -> "Line":
return Line(self.tags, source, self.command, self.params)

def copy(self) -> "Line":
return Line(self.tags, self.source, self.command, self.params)


def build(
command: str,
params: List[str]=[],
source: Optional[str]=None,
tags: Optional[Dict[str, str]]=None
) -> Line:
command: str,
params: List[str] = [],
source: Optional[str] = None,
tags: Optional[Dict[str, str]] = None,
) -> Line:
return Line(tags, source, command, params)


def _unescape_tag(value: str) -> str:
unescaped, escaped = "", list(value)
while escaped:
current = escaped.pop(0)
if current == "\\":
if escaped:
next = escaped.pop(0)
duo = current+next
duo = current + next
if duo in TAG_ESCAPED:
index = TAG_ESCAPED.index(duo)
unescaped += TAG_UNESCAPED[index]
Expand All @@ -66,14 +77,15 @@ def _unescape_tag(value: str) -> str:
unescaped += current
return unescaped


def _tokenise(line: str) -> Line:
tags: Optional[Dict[str, str]] = None
if line[0] == "@":
tags_s, _, line = line.partition(" ")
tags = {}
for part in tags_s[1:].split(";"):
key, _, value = part.partition("=")
tags[key] = _unescape_tag(value)
tags[key] = _unescape_tag(value)

line, trailing_sep, trailing = line.partition(" :")
params = list(filter(bool, line.split(" ")))
Expand All @@ -91,17 +103,16 @@ def _tokenise(line: str) -> Line:

return Line(tags, source, command, params)


def tokenise(
line: Union[str, bytes],
encoding: str="utf8",
fallback: str="latin-1"
) -> Line:
line: Union[str, bytes], encoding: str = "utf8", fallback: str = "latin-1"
) -> Line:

dline: str = ""
if isinstance(line, bytes):
if line[0] == ord(b"@"):
tags_b, sep, line = line.partition(b" ")
dline += (tags_b+sep).decode("utf8")
dline += (tags_b + sep).decode("utf8")
try:
dline += line.decode(encoding)
except UnicodeDecodeError:
Expand Down
9 changes: 6 additions & 3 deletions irctokens/stateful.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from typing import List, Optional
from .line import Line, tokenise

from .line import Line, tokenise


class StatefulDecoder(object):
def __init__(self, encoding: str="utf8", fallback: str="latin-1"):
def __init__(self, encoding: str = "utf8", fallback: str = "latin-1"):
self._encoding = encoding
self._fallback = fallback
self.clear()
Expand All @@ -26,8 +28,9 @@ def push(self, data: bytes) -> Optional[List[Line]]:
lines.append(tokenise(line, self._encoding, self._fallback))
return lines


class StatefulEncoder(object):
def __init__(self, encoding: str="utf8"):
def __init__(self, encoding: str = "utf8"):
self._encoding = encoding
self.clear()

Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"Operating System :: OS Independent",
"Operating System :: POSIX",
"Operating System :: Microsoft :: Windows",
"Topic :: Communications :: Chat :: Internet Relay Chat"
"Topic :: Communications :: Chat :: Internet Relay Chat",
],
python_requires='>=3.6'
python_requires=">=3.6",
)
8 changes: 4 additions & 4 deletions test/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .tokenise import *
from .format import *
from .format import *
from .hostmask import *
from .parser_tests import *
from .stateful_decode import *
from .stateful_encode import *
from .hostmask import *
from .parser_tests import *
from .tokenise import *
29 changes: 21 additions & 8 deletions test/format.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,50 @@
import unittest

import irctokens


class FormatTestTags(unittest.TestCase):
def test(self):
line = irctokens.build("PRIVMSG", ["#channel", "hello"],
tags={"id": "\\" + " " + ";" + "\r\n"}).format()
line = irctokens.build(
"PRIVMSG", ["#channel", "hello"], tags={"id": "\\" + " " + ";" + "\r\n"}
).format()
self.assertEqual(line, "@id=\\\\\\s\\:\\r\\n PRIVMSG #channel hello")

def test_missing(self):
line = irctokens.build("PRIVMSG", ["#channel", "hello"]).format()
self.assertEqual(line, "PRIVMSG #channel hello")

def test_none_value(self):
line = irctokens.build("PRIVMSG", ["#channel", "hello"],
tags={"a": None}).format()
line = irctokens.build(
"PRIVMSG", ["#channel", "hello"], tags={"a": None}
).format()
self.assertEqual(line, "@a PRIVMSG #channel hello")

def test_empty_value(self):
line = irctokens.build("PRIVMSG", ["#channel", "hello"], tags={"a": ""}
).format()
line = irctokens.build(
"PRIVMSG", ["#channel", "hello"], tags={"a": ""}
).format()
self.assertEqual(line, "@a PRIVMSG #channel hello")


class FormatTestSource(unittest.TestCase):
def test(self):
line = irctokens.build("PRIVMSG", ["#channel", "hello"],
source="nick!user@host").format()
line = irctokens.build(
"PRIVMSG", ["#channel", "hello"], source="nick!user@host"
).format()
self.assertEqual(line, ":nick!user@host PRIVMSG #channel hello")


class FormatTestCommand(unittest.TestCase):
def test_lowercase(self):
line = irctokens.build("privmsg").format()
self.assertEqual(line, "privmsg")

def test_uppercase(self):
line = irctokens.build("PRIVMSG").format()
self.assertEqual(line, "PRIVMSG")


class FormatTestTrailing(unittest.TestCase):
def test_space(self):
line = irctokens.build("PRIVMSG", ["#channel", "hello world"]).format()
Expand All @@ -48,13 +58,16 @@ def test_double_colon(self):
line = irctokens.build("PRIVMSG", ["#channel", ":helloworld"]).format()
self.assertEqual(line, "PRIVMSG #channel ::helloworld")


class FormatTestInvalidParam(unittest.TestCase):
def test_non_last_space(self):
def _inner():
irctokens.build("USER", ["user", "0 *", "real name"]).format()

self.assertRaises(ValueError, _inner)

def test_non_last_colon(self):
def _inner():
irctokens.build("PRIVMSG", [":#channel", "hello"]).format()

self.assertRaises(ValueError, _inner)
4 changes: 4 additions & 0 deletions test/hostmask.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import unittest

import irctokens


class HostmaskTest(unittest.TestCase):
def test_all(self):
hostmask = irctokens.hostmask("nick!user@host")
Expand Down Expand Up @@ -36,6 +38,8 @@ def test_line(self):

def test_none_source(self):
line = irctokens.tokenise("PRIVMSG #channel hello")

def _hostmask():
line.hostmask

self.assertRaises(ValueError, _hostmask)
Loading