Skip to content

Commit 2d6fb9d

Browse files
authored
Merge pull request #274 from Mastermind-U/add_contextmanager
Add contextmanager support. Thank you. I will see if, when I will make a new release.
2 parents 1d79734 + c67be0c commit 2d6fb9d

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

src/asn1.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from builtins import int
2323
from builtins import range
2424
from builtins import str
25+
from contextlib import contextmanager
2526
from enum import IntEnum
2627
from numbers import Number
2728

@@ -118,6 +119,46 @@ def leave(self): # type: () -> None
118119
self._emit_length(len(value))
119120
self._emit(value)
120121

122+
@contextmanager
123+
def construct(self, nr, cls=None): # type: (int, int) -> None
124+
"""This method - context manager calls enter and leave methods,
125+
for better code mapping.
126+
127+
Usage:
128+
```
129+
with encoder.construct(asn1.Numbers.Sequence):
130+
encoder.write(1)
131+
with encoder.construct(asn1.Numbers.Sequence):
132+
encoder.write('foo')
133+
encoder.write('bar')
134+
encoder.write(2)
135+
```
136+
encoder.output() will result following structure:
137+
SEQUENCE:
138+
INTEGER: 1
139+
SEQUENCE:
140+
STRING: foo
141+
STRING: bar
142+
INTEGER: 2
143+
144+
Args:
145+
nr (int): The desired ASN.1 type. Use ``Numbers`` enumeration.
146+
147+
cls (int): This optional parameter specifies the class
148+
of the constructed type. The default class to use is the
149+
universal class. Use ``Classes`` enumeration.
150+
151+
Returns:
152+
None
153+
154+
Raises:
155+
`Error`
156+
157+
"""
158+
self.enter(nr, cls)
159+
yield
160+
self.leave()
161+
121162
def write(self, value, nr=None, typ=None, cls=None): # type: (object, int, int, int) -> None
122163
"""This method encodes one ASN.1 tag and writes it to the output buffer.
123164

tests/test_asn1.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,41 @@ def test_long_tag_id(self):
279279
res = enc.output()
280280
assert res == b'\x3f\x83\xff\x7f\x03\x02\x01\x01'
281281

282+
def test_contextmanager_construct(self):
283+
enc = asn1.Encoder()
284+
enc.start()
285+
286+
with enc.construct(asn1.Numbers.Sequence):
287+
enc.write(1)
288+
enc.write(b'foo')
289+
290+
res = enc.output()
291+
assert res == b'\x30\x08\x02\x01\x01\x04\x03foo'
292+
293+
def test_contextmanager_calls_enter(self):
294+
class TestEncoder(asn1.Encoder):
295+
def enter(self, nr, cls=None):
296+
raise RuntimeError()
297+
298+
enc = TestEncoder()
299+
enc.start()
300+
301+
with pytest.raises(RuntimeError):
302+
with enc.construct(asn1.Numbers.Sequence):
303+
enc.write(1)
304+
305+
def test_contextmanager_calls_leave(self):
306+
class TestEncoder(asn1.Encoder):
307+
def leave(self):
308+
raise RuntimeError()
309+
310+
enc = TestEncoder()
311+
enc.start()
312+
313+
with pytest.raises(RuntimeError):
314+
with enc.construct(asn1.Numbers.Sequence):
315+
enc.write(1)
316+
282317
def test_long_tag_length(self):
283318
enc = asn1.Encoder()
284319
enc.start()

0 commit comments

Comments
 (0)