Skip to content

Commit fbaff6b

Browse files
authored
Merge pull request #81 from jap/bytes-helpers
add some helpers to deal with streams of bytes
2 parents 5be0cd3 + be1cbc0 commit fbaff6b

File tree

3 files changed

+43
-9
lines changed

3 files changed

+43
-9
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ repos:
44
hooks:
55
- id: trailing-whitespace
66
- id: end-of-file-fixer
7-
- repo: https://gitlab.com/pycqa/flake8
7+
- repo: https://github.com/pycqa/flake8
88
rev: 3.8.4
99
hooks:
1010
- id: flake8

src/parsy/__init__.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import re
66
from dataclasses import dataclass
77
from functools import wraps
8-
from typing import Any, Callable, FrozenSet
8+
from typing import Any, AnyStr, Callable, FrozenSet
99

1010
__version__ = "2.1"
1111

@@ -166,10 +166,23 @@ def combine_dict(self, combine_fn: Callable) -> Parser:
166166

167167
def concat(self) -> Parser:
168168
"""
169-
Returns a parser that concatenates together (as a string) the previously
170-
produced values.
169+
Returns a parser that concatenates together the previously produced values.
170+
171+
This parser will join the values using the type of the input stream, so
172+
when feeding bytes to the parser, the items to be joined must also be bytes.
171173
"""
172-
return self.map("".join)
174+
175+
@Parser
176+
def parser(stream: bytes | str, index: int) -> Result:
177+
joiner = type(stream)()
178+
result = self(stream, index)
179+
if result.status:
180+
next_parser: Parser = success(joiner.join(result.value))
181+
return next_parser(stream, result.index).aggregate(result)
182+
else:
183+
return result
184+
185+
return parser
173186

174187
def then(self, other: Parser) -> Parser:
175188
"""
@@ -516,13 +529,16 @@ def fail(expected: str) -> Parser:
516529
return Parser(lambda _, index: Result.failure(index, expected))
517530

518531

519-
def string(expected_string: str, transform: Callable[[str], str] = noop) -> Parser:
532+
def string(expected_string: AnyStr, transform: Callable[[AnyStr], AnyStr] = noop) -> Parser:
520533
"""
521534
Returns a parser that expects the ``expected_string`` and produces
522535
that string value.
523536
524537
Optionally, a transform function can be passed, which will be used on both
525538
the expected string and tested string.
539+
540+
This parser can also be instantiated with a bytes value, in which case it can
541+
should be applied to a stream of bytes.
526542
"""
527543

528544
slen = len(expected_string)

tests/test_parsy.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@
3232

3333

3434
class TestParser(unittest.TestCase):
35-
def test_string(self):
35+
def test_string_str(self):
3636
parser = string("x")
3737
self.assertEqual(parser.parse("x"), "x")
3838

3939
self.assertRaises(ParseError, parser.parse, "y")
4040

41-
def test_string_transform(self):
41+
def test_string_transform_str(self):
4242
parser = string("x", transform=lambda s: s.lower())
4343
self.assertEqual(parser.parse("x"), "x")
4444
self.assertEqual(parser.parse("X"), "x")
@@ -53,6 +53,19 @@ def test_string_transform_2(self):
5353

5454
self.assertRaises(ParseError, parser.parse, "dog")
5555

56+
def test_string_bytes(self):
57+
parser = string(b"x")
58+
self.assertEqual(parser.parse(b"x"), b"x")
59+
60+
self.assertRaises(ParseError, parser.parse, b"y")
61+
62+
def test_string_transform_bytes(self):
63+
parser = string(b"x", transform=lambda s: s.lower())
64+
self.assertEqual(parser.parse(b"x"), b"x")
65+
self.assertEqual(parser.parse(b"X"), b"x")
66+
67+
self.assertRaises(ParseError, parser.parse, b"y")
68+
5669
def test_regex_str(self):
5770
parser = regex(r"[0-9]")
5871

@@ -157,11 +170,16 @@ def test_combine_dict_skip_underscores(self):
157170
).combine_dict(Pair)
158171
self.assertEqual(parser.parse("ABC 123"), Pair(word="ABC", number=123))
159172

160-
def test_concat(self):
173+
def test_concat_str(self):
161174
parser = letter.many().concat()
162175
self.assertEqual(parser.parse(""), "")
163176
self.assertEqual(parser.parse("abc"), "abc")
164177

178+
def test_concat_bytes(self):
179+
parser = any_char.many().concat()
180+
self.assertEqual(parser.parse(b""), b"")
181+
self.assertEqual(parser.parse(b"abc"), b"abc")
182+
165183
def test_generate(self):
166184
x = y = None
167185

0 commit comments

Comments
 (0)