Package pyx12 :: Module segment
[hide private]

Source Code for Module pyx12.segment

  1  ###################################################################### 
  2  # Copyright (c) 2001-2005 Kalamazoo Community Mental Health Services, 
  3  #   John Holland <jholland@kazoocmh.org> <john@zoner.org> 
  4  # All rights reserved. 
  5  # 
  6  # This software is licensed as described in the file LICENSE.txt, which 
  7  # you should have received as part of this distribution. 
  8  # 
  9  ###################################################################### 
 10   
 11  #    $Id: segment.py 1125 2007-06-21 21:30:52Z johnholland $ 
 12   
 13  """ 
 14  Implements an interface to a x12 segment. 
 15   
 16  A segment is comprised of a segment identifier and a sequence of elements. 
 17  An element can be a simple element or a composite.  A simple element is  
 18  treated as a composite element with one sub-element. 
 19   
 20  All indexing is zero based. 
 21  """ 
 22   
 23  #import string 
 24   
 25  from pyx12.errors import EngineError 
 26   
27 -class Element(object):
28 """ 29 Holds a simple element, which is just a simple string. 30 """ 31
32 - def __init__(self, ele_str):
33 """ 34 @param ele_str: 1::2 35 @type ele_str: string 36 37 """ 38 self.value = ele_str
39
40 - def __len__(self):
41 """ 42 @rtype: int 43 """ 44 return 1
45
46 - def __repr__(self):
47 """ 48 @rtype: string 49 """ 50 return self.value
51
52 - def format(self):
53 """ 54 @rtype: string 55 """ 56 return self.value
57
58 - def get_value(self):
59 """ 60 @rtype: string 61 """ 62 return self.value
63
64 - def set_value(self, elem_str):
65 """ 66 @param elem_str: Element string value 67 @type elem_str: string 68 """ 69 self.value = elem_str
70
71 - def is_composite(self):
72 """ 73 @rtype: boolean 74 """ 75 return False
76
77 - def is_element(self):
78 """ 79 @rtype: boolean 80 """ 81 return True
82
83 - def is_empty(self):
84 """ 85 @rtype: boolean 86 """ 87 if self.value and self.value != '': 88 return False 89 else: 90 return True
91
92 -class Composite(object):
93 """ 94 Can be a simple element or a composite. 95 A simple element is treated as a composite element with one sub-element. 96 """ 97 # Attributes: 98 99 # Operations
100 - def __init__(self, ele_str, subele_term=None):
101 """ 102 @type ele_str: string 103 """ 104 self.subele_term = subele_term 105 self.subele_term_orig = subele_term 106 members = ele_str.split(self.subele_term) 107 self.elements = [] 108 for elem in members: 109 self.elements.append(Element(elem))
110
111 - def __getitem__(self, idx):
112 """ 113 returns Element instance for idx 114 """ 115 return self.elements[idx]
116
117 - def __setitem__(self, idx, val):
118 """ 119 1 based index 120 [0] throws exception 121 sets element value for idx 122 """ 123 self.elements[idx] = val
124
125 - def __len__(self):
126 """ 127 @rtype: int 128 """ 129 return len(self.elements)
130
131 - def __repr__(self):
132 """ 133 @rtype: string 134 """ 135 return self.format(self.subele_term)
136
137 - def format(self, subele_term=None):
138 """ 139 Format a composite 140 141 @return: string 142 """ 143 if subele_term is None: 144 subele_term = self.subele_term 145 for i in range(len(self.elements)-1, -1, -1): 146 if not self.elements[i].is_empty(): 147 break 148 return '%s' % (subele_term.join(map(Element.__repr__, \ 149 self.elements[:i+1])))
150
151 - def get_value(self):
152 """ 153 Get value of simple element 154 """ 155 if len(self.elements) == 1: 156 return self.elements[0].get_value() 157 else: 158 raise IndexError, 'value of composite is undefined'
159
160 - def set_subele_term(self, subele_term):
161 """ 162 @param subele_term: Sub-element terminator value 163 @type subele_term: string 164 """ 165 self.subele_term = subele_term
166
167 - def is_composite(self):
168 """ 169 @rtype: boolean 170 """ 171 if len(self.elements) > 1: 172 return True 173 else: 174 return False
175
176 - def is_element(self):
177 """ 178 @rtype: boolean 179 """ 180 if len(self.elements) == 1: 181 return True 182 else: 183 return False
184
185 - def is_empty(self):
186 """ 187 @rtype: boolean 188 """ 189 for ele in self.elements: 190 if not ele.is_empty(): 191 return False 192 return True
193 194
195 -class Segment(object):
196 """ 197 Encapsulates a X12 segment. Contains composites. 198 """ 199 # Attributes: 200 201 # Operations
202 - def __init__(self, seg_str, seg_term, ele_term, subele_term):
203 """ 204 """ 205 self.seg_term = seg_term 206 self.seg_term_orig = seg_term 207 self.ele_term = ele_term 208 self.ele_term_orig = ele_term 209 self.subele_term = subele_term 210 self.subele_term_orig = subele_term 211 self.seg_id = None 212 if seg_str and seg_str[-1] == seg_term: 213 elems = seg_str[:-1].split(self.ele_term) 214 else: 215 elems = seg_str.split(self.ele_term) 216 self.elements = [] 217 if elems: 218 self.seg_id = elems[0] 219 for ele in elems[1:]: 220 if self.seg_id == 'ISA': 221 #Special handling for ISA segment 222 #guarantee subele_term will not be matched 223 self.elements.append(Composite(ele, ele_term)) 224 else: 225 self.elements.append(Composite(ele, subele_term))
226
227 - def __repr__(self):
228 """ 229 @rtype: string 230 """ 231 return self.format(self.seg_term, self.ele_term, self.subele_term)
232 233 # def __getitem__(self, idx): 234 # """ 235 # returns element instance 236 # """ 237 # return self.elements[idx] 238 239 # def __setitem__(self, idx, val): 240 # """ 241 # """ 242 # self.elements[idx] = Composite(val, self.subele_term) 243
244 - def append(self, val):
245 """ 246 Append a composite to the segment 247 248 @param val: String value of composite 249 @type val: string 250 """ 251 self.elements.append(Composite(val, self.subele_term))
252
253 - def __len__(self):
254 """ 255 @rtype: int 256 """ 257 return len(self.elements)
258
259 - def get_seg_id(self):
260 """ 261 @rtype: string 262 """ 263 return self.seg_id
264
265 - def _parse_refdes(self, ref_des):
266 """ 267 Format of ref_des: 268 - a simple element: TST02 269 - a composite: TST03 where TST03 is a composite 270 - a sub-element: TST03-2 271 - or any of the above with the segment ID omitted (02, 03, 03-1) 272 273 @param ref_des: X12 Reference Designator 274 @type ref_des: string 275 @rtype: tuple(ele_idx, subele_idx) 276 @raise EngineError: If the given ref_des does not match the segment ID 277 or if the indexes are not valid integers 278 """ 279 if ref_des is None or ref_des == '': 280 raise EngineError, 'Blank Reference Designator' 281 if ref_des[0].isalpha(): 282 if ref_des[:len(self.seg_id)] != self.seg_id: 283 err_str = 'Invalid Reference Designator: %s, seg_id: %s' \ 284 % (ref_des, self.seg_id) 285 raise EngineError, err_str 286 rest = ref_des[len(self.seg_id):] 287 else: 288 rest = ref_des 289 dash = rest.find('-') 290 try: 291 if dash == -1: 292 ele_idx = int(rest) - 1 293 comp_idx = None 294 else: 295 ele_idx = int(rest[:dash]) - 1 296 comp_idx = int(rest[dash+1:]) - 1 297 except ValueError: 298 raise EngineError, 'Invalid Reference Designator indexes: %s' \ 299 % (ref_des) 300 return (ele_idx, comp_idx)
301
302 - def get(self, ref_des):
303 """ 304 @param ref_des: X12 Reference Designator 305 @type ref_des: string 306 @return: Element or Composite 307 @rtype: L{segment.Composite} 308 """ 309 (ele_idx, comp_idx) = self._parse_refdes(ref_des) 310 if ele_idx >= self.__len__(): 311 return None 312 if comp_idx is None: 313 return self.elements[ele_idx] 314 else: 315 if comp_idx >= self.elements[ele_idx].__len__(): 316 return None 317 return self.elements[ele_idx][comp_idx]
318
319 - def get_value(self, ref_des):
320 """ 321 @param ref_des: X12 Reference Designator 322 @type ref_des: string 323 """ 324 comp1 = self.get(ref_des) 325 if comp1 is None: 326 return None 327 else: 328 return comp1.format()
329
330 - def get_value_by_ref_des(self, ref_des):
331 """ 332 @param ref_des: X12 Reference Designator 333 @type ref_des: string 334 @attention: Deprecated - use get_value 335 """ 336 return self.get(ref_des).format()
337
338 - def set(self, ref_des, val):
339 """ 340 Set the value of an element or subelement identified by the 341 Reference Designator 342 343 @param ref_des: X12 Reference Designator 344 @type ref_des: string 345 @param val: New value 346 @type val: string 347 """ 348 (ele_idx, comp_idx) = self._parse_refdes(ref_des) 349 while len(self.elements) <= ele_idx: 350 self.elements.append(Composite('', self.subele_term)) 351 if comp_idx is None: 352 self.elements[ele_idx] = Composite(val, self.subele_term) 353 else: 354 while len(self.elements[ele_idx]) <= comp_idx: 355 self.elements[ele_idx].elements.append(Element('')) 356 self.elements[ele_idx][comp_idx] = Element(val)
357
358 - def is_element(self, ref_des):
359 """ 360 @param ref_des: X12 Reference Designator 361 @type ref_des: string 362 """ 363 ele_idx = self._parse_refdes(ref_des)[0] 364 return self.elements[ele_idx].is_element()
365
366 - def is_composite(self, ref_des):
367 """ 368 @param ref_des: X12 Reference Designator 369 @type ref_des: string 370 """ 371 ele_idx = self._parse_refdes(ref_des)[0] 372 return self.elements[ele_idx].is_composite()
373
374 - def ele_len(self, ref_des):
375 """ 376 @param ref_des: X12 Reference Designator 377 @type ref_des: string 378 @return: number of sub-elements in an element or composite 379 @rtype: int 380 """ 381 ele_idx = self._parse_refdes(ref_des)[0] 382 return len(self.elements[ele_idx])
383
384 - def set_seg_term(self, seg_term):
385 """ 386 @param seg_term: Segment terminator 387 @type seg_term: string 388 """ 389 self.seg_term = seg_term
390
391 - def set_ele_term(self, ele_term):
392 """ 393 @param ele_term: Element terminator 394 @type ele_term: string 395 """ 396 self.ele_term = ele_term
397
398 - def set_subele_term(self, subele_term):
399 """ 400 @param subele_term: Sub-element terminator 401 @type subele_term: string 402 """ 403 self.subele_term = subele_term
404 405 # def set_eol(self, eol): 406 # self.eol = eol 407
408 - def format(self, seg_term=None, ele_term=None, subele_term=None):
409 """ 410 @rtype: string 411 """ 412 if seg_term is None: 413 seg_term = self.seg_term 414 if ele_term is None: 415 ele_term = self.ele_term 416 if subele_term is None: 417 subele_term = self.subele_term 418 str_elems = [] 419 i = 0 420 for i in range(len(self.elements)-1, -1, -1): 421 if not self.elements[i].is_empty(): 422 break 423 for ele in self.elements[:i+1]: 424 str_elems.append(ele.format(subele_term)) 425 #str_elems 426 return '%s%s%s%s' % (self.seg_id, ele_term, \ 427 ele_term.join(str_elems), \ 428 seg_term)
429
430 - def format_ele_list(self, str_elems, subele_term=None):
431 """ 432 Modifies the parameter str_elems 433 Strips trailing empty composites 434 """ 435 if subele_term is None: 436 subele_term = self.subele_term 437 # Find last non-empty composite 438 for i in range(len(self.elements)-1, -1, -1): 439 if not self.elements[i].is_empty(): 440 break 441 for ele in self.elements[:i+1]: 442 str_elems.append(ele.format(subele_term))
443
444 - def is_empty(self):
445 """ 446 @rtype: boolean 447 """ 448 if len(self.elements) == 0: 449 return True 450 for ele in self.elements: 451 if not ele.is_empty(): 452 return False 453 return True
454
455 - def is_seg_id_valid(self):
456 """ 457 Is the Segment identifier the correct length 458 @rtype: boolean 459 """ 460 if not self.seg_id or len(self.seg_id) < 2 or len(self.seg_id) > 3: 461 return False 462 else: 463 return True
464