34
34
35
35
36
36
class AbstractSegmentsContainer :
37
- """Represent a collection of EDI Segments for both reading and writing .
37
+ """Abstract base class of subclasses containing collection of segments .
38
38
39
- You should not instantiate AbstractSegmentsContainer itself, but subclass it use that.
39
+ :class:`AbstractSegmentsContainer` is the superclass of several classes such as
40
+ :class:`RawSegmentCollection` and :class:`Interchange` and contains methods common
41
+ to them.
40
42
41
- The segments list in AbstractSegmentsContainer includes header and footer segments too.
42
- Inheriting envelopes must NOT include these elements in .segments, as get_header_element() and
43
- get_footer_element() should provide these elements on-the-fly.
43
+ **Implementation detail:** Subclasses must set :attr:`HEADER_TAG` and
44
+ :attr:`FOOTER_TAG`.
44
45
45
- Inheriting classes must set HEADER_TAG and FOOTER_TAG
46
+ :param extra_header_elements: A list of elements to be appended at the end
47
+ of the header segment (same format as :class:`~pydifact.segments.Segment`
48
+ constructor elements).
49
+
50
+ :param characters: The set of control characters
51
+
52
+ .. attribute:: segments
53
+
54
+ The segments that comprise the container. This does not include the envelope
55
+ (that is, the header and footer) segments. To get the envolope segments, use
56
+ as :meth:`get_header_segment` and :meth:`get_footer_segment`.
57
+
58
+ .. attribute:: characters
59
+
60
+ The control characters (a :class:`~pydifact.control.Characters` object).
46
61
"""
47
62
48
63
HEADER_TAG : str = None
@@ -53,13 +68,6 @@ def __init__(
53
68
extra_header_elements : List [Union [str , List [str ]]] = None ,
54
69
characters : Optional [Characters ] = None ,
55
70
):
56
- """
57
- :param extra_header_elements: a list of elements to be appended at the end
58
- of the header segment (same format as Segment() constructor *elements).
59
- :param characters: the set of control characters
60
- """
61
-
62
- # The segments that make up this message
63
71
self .segments = []
64
72
65
73
# set of control characters
@@ -81,10 +89,9 @@ def from_str(
81
89
) -> "AbstractSegmentsContainer" :
82
90
"""Create an instance from a string.
83
91
84
- This method is intended for usage in inheriting classes, not it AbstractSegmentsContainer itself.
85
- :param string: The EDI content
86
- :param parser: A parser to convert the tokens to segments, defaults to `Parser`
87
- :param characters: the set of control characters
92
+ :param string: The EDI content.
93
+ :param parser: A parser to convert the tokens to segments; defaults to `Parser`.
94
+ :param characters: The set of control characters.
88
95
"""
89
96
if parser is None :
90
97
parser = Parser (characters = characters )
@@ -99,11 +106,12 @@ def from_segments(
99
106
segments : Union [List , Iterable ],
100
107
characters : Optional [Characters ] = None ,
101
108
) -> "AbstractSegmentsContainer" :
102
- """Create a new AbstractSegmentsContainer instance from a iterable list of segments.
109
+ """Create an instance from a list of segments.
103
110
104
- :param segments: The segments of the EDI interchange
105
- :param characters: the set of control characters
111
+ :param segments: The segments of the EDI interchange.
106
112
:type segments: list/iterable of Segment
113
+
114
+ :param characters: The set of control characters.
107
115
"""
108
116
109
117
# create a new instance of AbstractSegmentsContainer and return it
@@ -115,11 +123,13 @@ def get_segments(
115
123
name : str ,
116
124
predicate : Callable = None , # Python3.9+ Callable[[Segment], bool]
117
125
) -> list :
118
- """Get all the segments that match the requested name.
126
+ """Get all segments that match the requested name.
119
127
120
- :param name: The name of the segments to return
121
- :param predicate: Optional predicate callable that returns True if the given segment matches a condition
122
- :rtype: list of Segment
128
+ :param name: The name of the segments to return.
129
+ :param predicate: Optional callable that returns True if the given
130
+ segment matches a condition.
131
+
132
+ :rtype: list of :class:`Segment` objects.
123
133
"""
124
134
for segment in self .segments :
125
135
if segment .tag == name and (predicate is None or predicate (segment )):
@@ -132,10 +142,11 @@ def get_segment(
132
142
) -> Optional [Segment ]:
133
143
"""Get the first segment that matches the requested name.
134
144
135
- :return: The requested segment, or None if not found
136
- :param name: The name of the segment to return
145
+ :param name: The name of the segment to return.
137
146
:param predicate: Optional predicate that must match on the segments
138
- to return
147
+ to return.
148
+
149
+ :return: The requested segment, or None if not found.
139
150
"""
140
151
for segment in self .get_segments (name , predicate ):
141
152
return segment
@@ -146,17 +157,18 @@ def split_by(
146
157
self ,
147
158
start_segment_tag : str ,
148
159
) -> Iterable : # Python3.9+ Iterable["RawSegmentCollection"]
149
- """Split a segment collection by tag.
150
-
151
- Everything before the first start segment is ignored, so if no matching
152
- start segment is found at all, returned result is empty.
160
+ """Split the segment collection by tag.
153
161
162
+ Assuming the collection contains tags ``["A", "B", "A", "A", "B", "D"]``,
163
+ ``split_by("A")`` would return ``[["A", "B"], ["A"], ["A", "B", "D"]]``.
164
+ Everything before the first start segment is ignored, so if no matching start
165
+ segment is found at all, the returned result is empty.
154
166
155
167
:param start_segment_tag:
156
168
the segment tag we want to use as separator
157
169
158
- :return: generator of segment collections. The start tag is included in
159
- each yielded collection
170
+ :return: Generator of segment collections. The start tag is included in
171
+ each yielded collection.
160
172
"""
161
173
current_list = None
162
174
@@ -176,13 +188,15 @@ def split_by(
176
188
def add_segments (
177
189
self , segments : Union [List [Segment ], Iterable ]
178
190
) -> "AbstractSegmentsContainer" :
179
- """Add multiple segments to the collection. Passing a UNA segment means setting/overriding the control
180
- characters and setting the serializer to output the Service String Advice. If you wish to change the control
181
- characters from the default and not output the Service String Advice, change self.characters instead,
182
- without passing a UNA Segment.
191
+ """Append a list of segments to the collection.
192
+
193
+ Passing a ``UNA`` segment means setting/overriding the control characters and
194
+ setting the serializer to output the Service String Advice. If you wish to
195
+ change the control characters from the default and not output the Service String
196
+ Advice, change :attr:`characters` instead, without passing a UNA Segment.
183
197
184
- :param segments: The segments to add
185
- :type segments: list or iterable of Segments
198
+ :param segments: The segments to add.
199
+ :type segments: List or iterable of :class:`~pydifact.segments.Segment` objects.
186
200
"""
187
201
for segment in segments :
188
202
self .add_segment (segment )
@@ -192,31 +206,30 @@ def add_segments(
192
206
def add_segment (self , segment : Segment ) -> "AbstractSegmentsContainer" :
193
207
"""Append a segment to the collection.
194
208
195
- Note: skips segments that are header or footer tags of this segment container type.
209
+ Note: skips segments that are header or footer tags of this segment container
210
+ type.
211
+
196
212
:param segment: The segment to add
197
213
"""
198
214
if not segment .tag in (self .HEADER_TAG , self .FOOTER_TAG ):
199
215
self .segments .append (segment )
200
216
return self
201
217
202
218
def get_header_segment (self ) -> Optional [Segment ]:
203
- """Craft and return this container header segment (if any)
204
-
205
- :returns: None if there is no header for that container
219
+ """Return the header segment or ``None`` if there is no header.
206
220
"""
207
221
return None
208
222
209
223
def get_footer_segment (self ) -> Optional [Segment ]:
210
- """Craft and return this container footer segment (if any)
211
-
212
- :returns: None if there is no footer for that container
224
+ """Return the footer segment or ``None`` if there is no footer.
213
225
"""
214
226
return None
215
227
216
228
def serialize (self , break_lines : bool = False ) -> str :
217
- """Serialize all the segments added to this object.
229
+ """Return the string representation of the object.
218
230
219
- :param break_lines: if True, insert line break after each segment terminator.
231
+ :param break_lines: If ``True``, inserts line break after each segment
232
+ terminator.
220
233
"""
221
234
header = self .get_header_segment ()
222
235
footer = self .get_footer_segment ()
@@ -235,18 +248,13 @@ def serialize(self, break_lines: bool = False) -> str:
235
248
)
236
249
237
250
def validate (self ):
238
- """Validates this container .
251
+ """Validate the object .
239
252
240
- This method must be overridden in implementing subclasses, and should make sure that
241
- the container is implemented correctly.
242
-
243
- It does not return anything and should raise an Exception in case of errors.
253
+ Raises an exception if the object is invalid.
244
254
"""
245
255
raise NotImplementedError
246
256
247
257
def __str__ (self ) -> str :
248
- """Allow the object to be serialized by casting to a string."""
249
-
250
258
return self .serialize ()
251
259
252
260
@@ -411,9 +419,9 @@ class Interchange(FileSourcableMixin, UNAHandlingMixin, AbstractSegmentsContaine
411
419
412
420
Optional features of UNB are not yet supported.
413
421
414
- Functional groups are not yet supported
422
+ Functional groups are not yet supported.
415
423
416
- Messages are supported, see get_message() and get_message( ), but are
424
+ Messages are supported ( see :meth:` get_message` ), but are
417
425
optional: interchange segments can be accessed without going through
418
426
messages.
419
427
0 commit comments