1
2
3
4
5
6
7
8
9
10
11
12
13 """
14 External Codes interface
15 """
16
17 import os, os.path
18
19 import cPickle
20 import libxml2
21 import datetime
22
23 from stat import ST_MTIME
24
25
26
27 from pyx12.errors import EngineError, XML_Reader_Error
28
30 """Class for code modules errors."""
31
32 NodeType = {'element_start': 1, 'element_end': 15, 'attrib': 2, 'text': 3, \
33 'CData': 4, 'entity_ref': 5, 'entity_decl':6, 'pi': 7, 'comment': 8, \
34 'doc': 9, 'dtd': 10, 'doc_frag': 11, 'notation': 12}
35
36
38 """
39 Validates an ID against an external list of codes
40 """
41
42 - def __init__(self, base_path, exclude=None):
43 """
44 Initialize the external list of codes
45 @param base_path: path to codes.xml
46 @type base_path: string
47 @param exclude: comma separated string of external codes to ignore
48 @type exclude: string
49
50 @note: self.codes - map of a tuple of two dates and a list of codes
51 {codeset_id: (eff_dte, exp_dte, [code_values])}
52 """
53
54 self.codes = {}
55 code_file = base_path + '/codes.xml'
56 pickle_file = '%s.%s' % (os.path.splitext(code_file)[0], 'pkl')
57
58 codeset_id = None
59 base_name = None
60
61
62 if exclude is None:
63 self.exclude_list = []
64 else:
65 self.exclude_list = exclude.split(',')
66
67 base_level = 0
68
69 try:
70 if os.stat(code_file)[ST_MTIME] < os.stat(pickle_file)[ST_MTIME]:
71 self.codes = cPickle.load(open(pickle_file))
72 else:
73 raise CodesError, "reload codes"
74 except:
75 try:
76 reader = libxml2.newTextReaderFilename(code_file)
77 except:
78 raise EngineError, 'Code file not found: %s' % (code_file)
79 try:
80 ret = reader.Read()
81 if ret == -1:
82 raise XML_Reader_Error, 'Read Error'
83 elif ret == 0:
84 raise XML_Reader_Error, 'End of Map File'
85 while ret == 1:
86 if reader.NodeType() == NodeType['element_start']:
87 cur_name = reader.Name()
88 if cur_name == 'codeset':
89 base_level = reader.Depth()
90 base_name = 'codeset'
91 elif cur_name == 'version':
92 code_list = []
93 eff_dte = None
94 exp_dte = None
95 base_name = 'version'
96 elif reader.NodeType() == NodeType['element_end']:
97 if reader.Name() == 'codeset':
98 self.codes[codeset_id] = (eff_dte, exp_dte, \
99 code_list)
100
101
102
103
104
105
106
107
108 cur_name = ''
109 elif reader.NodeType() == NodeType['text'] and \
110 base_level + 1 <= reader.Depth():
111 if cur_name == 'id':
112 if base_name == 'codeset':
113 codeset_id = reader.Value()
114
115 elif cur_name == 'code':
116 code_list.append(reader.Value())
117 elif cur_name == 'eff_dte':
118 eff_dte = reader.Value()
119 elif cur_name == 'exp_dte':
120 exp_dte = reader.Value()
121
122 ret = reader.Read()
123 if ret == -1:
124 raise XML_Reader_Error, 'Read Error'
125 elif ret == 0:
126 raise XML_Reader_Error, 'End of Map File'
127 except XML_Reader_Error:
128 pass
129
130
131
132
133
134
135 - def isValid(self, key, code, check_dte=None):
136 """
137 Is the code in the list identified by key
138 @param key: the external codeset identifier
139 @type key: string
140 @param code: code to be verified
141 @type code: string
142 @param check_dte: YYYYMMDD - Date on which to
143 check code validity. eg 20040514
144 @type check_dte: string
145 @return: True if code is valid, False if not
146 @rtype: boolean
147 """
148
149
150 if not key:
151 raise EngineError, 'bad key %s' % (key)
152
153
154 else:
155 if key in self.exclude_list:
156 return True
157 if not self.codes.has_key(key):
158 raise EngineError, 'External Code "%s" is not defined' \
159 % (key)
160 if check_dte is None:
161 code_list = self.codes[key][2]
162 if code in code_list:
163 return True
164 else:
165 if len(check_dte) != 8:
166 raise EngineError, 'Bad check date %s' & (check_dte)
167 dt_check_dte = datetime.date(int(check_dte[:4]), \
168 int(check_dte[4:6]), int(check_dte[-2:]))
169 eff_dte = self.codes[key][0]
170 exp_dte = self.codes[key][1]
171 code_list = self.codes[key][2]
172
173
174 if eff_dte != None:
175 dt_eff_dte = datetime.date(int(eff_dte[:4]), \
176 int(eff_dte[4:6]), int(eff_dte[-2:]))
177 else:
178 dt_eff_dte = dt_check_dte.min
179 if exp_dte != None:
180 dt_exp_dte = datetime.date(int(exp_dte[:4]), \
181 int(exp_dte[4:6]), int(exp_dte[-2:]))
182 else:
183 dt_exp_dte = dt_check_dte.max
184 if dt_check_dte >= dt_eff_dte and dt_check_dte <= dt_exp_dte:
185 if code in code_list:
186 return True
187 return False
188
190 for key in self.codes.keys():
191 print self.codes[key][:10]
192