testgres.postgres-configuration 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. testgres/postgres_configuration/__init__.py +22 -0
  2. testgres/postgres_configuration/abstract/v00/configuration.py +435 -0
  3. testgres/postgres_configuration/core/bugcheck_error.py +219 -0
  4. testgres/postgres_configuration/core/controller_utils.py +982 -0
  5. testgres/postgres_configuration/core/data_verificator.py +60 -0
  6. testgres/postgres_configuration/core/handlers.py +483 -0
  7. testgres/postgres_configuration/core/helpers.py +95 -0
  8. testgres/postgres_configuration/core/model.py +296 -0
  9. testgres/postgres_configuration/core/option/handlers/add/option_handler_to_add__std.py +38 -0
  10. testgres/postgres_configuration/core/option/handlers/get_value/option_handler_to_get_value__std__simple.py +36 -0
  11. testgres/postgres_configuration/core/option/handlers/get_value/option_handler_to_get_value__std__union_list.py +36 -0
  12. testgres/postgres_configuration/core/option/handlers/prepare_get_value/option_handler_to_prepare_get_value__std__bool.py +31 -0
  13. testgres/postgres_configuration/core/option/handlers/prepare_get_value/option_handler_to_prepare_get_value__std__generic.py +41 -0
  14. testgres/postgres_configuration/core/option/handlers/prepare_get_value/option_handler_to_prepare_get_value__std__int.py +31 -0
  15. testgres/postgres_configuration/core/option/handlers/prepare_get_value/option_handler_to_prepare_get_value__std__str.py +31 -0
  16. testgres/postgres_configuration/core/option/handlers/prepare_get_value/option_handler_to_prepare_get_value__std__unique_str_list.py +46 -0
  17. testgres/postgres_configuration/core/option/handlers/prepare_set_value/option_handler_to_prepare_set_value__std__bool.py +115 -0
  18. testgres/postgres_configuration/core/option/handlers/prepare_set_value/option_handler_to_prepare_set_value__std__generic.py +41 -0
  19. testgres/postgres_configuration/core/option/handlers/prepare_set_value/option_handler_to_prepare_set_value__std__int.py +44 -0
  20. testgres/postgres_configuration/core/option/handlers/prepare_set_value/option_handler_to_prepare_set_value__std__str.py +37 -0
  21. testgres/postgres_configuration/core/option/handlers/prepare_set_value/option_handler_to_prepare_set_value__std__unique_str_list.py +63 -0
  22. testgres/postgres_configuration/core/option/handlers/prepare_set_value_item/option_handler_to_prepare_set_value_item__std__str.py +37 -0
  23. testgres/postgres_configuration/core/option/handlers/set_value/option_handler_to_set_value__std__simple.py +38 -0
  24. testgres/postgres_configuration/core/option/handlers/set_value_item/option_handler_to_set_value_item__std__unique.py +38 -0
  25. testgres/postgres_configuration/core/option/handlers/write/option_handler_to_write__std__bool.py +42 -0
  26. testgres/postgres_configuration/core/option/handlers/write/option_handler_to_write__std__generic.py +51 -0
  27. testgres/postgres_configuration/core/option/handlers/write/option_handler_to_write__std__int.py +27 -0
  28. testgres/postgres_configuration/core/option/handlers/write/option_handler_to_write__std__str.py +36 -0
  29. testgres/postgres_configuration/core/option/handlers/write/option_handler_to_write__std__unique_str_list.py +37 -0
  30. testgres/postgres_configuration/core/raise_error.py +365 -0
  31. testgres/postgres_configuration/core/read_utils.py +308 -0
  32. testgres/postgres_configuration/core/write_utils.py +112 -0
  33. testgres/postgres_configuration/implementation/v00/configuration_base.py +4408 -0
  34. testgres/postgres_configuration/implementation/v00/configuration_std.py +538 -0
  35. testgres/postgres_configuration/os/abstract/configuration_os_ops.py +98 -0
  36. testgres/postgres_configuration/os/local/configuration_os_ops.py +154 -0
  37. testgres_postgres_configuration-0.1.0.dist-info/METADATA +25 -0
  38. testgres_postgres_configuration-0.1.0.dist-info/RECORD +40 -0
  39. testgres_postgres_configuration-0.1.0.dist-info/WHEEL +5 -0
  40. testgres_postgres_configuration-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,365 @@
1
+ # //////////////////////////////////////////////////////////////////////////////
2
+ # Postgres Pro. PostgreSQL Configuration Python Library.
3
+
4
+ import datetime
5
+
6
+ # //////////////////////////////////////////////////////////////////////////////
7
+ # RaiseError
8
+
9
+
10
+ class RaiseError:
11
+ def MethodIsNotImplemented(classType: type, methodName: str):
12
+ assert type(classType) == type
13
+ assert type(methodName) == str
14
+ assert methodName != ""
15
+
16
+ errMsg = "Method {0}::{1} is not implemented.".format(
17
+ classType.__name__, methodName
18
+ )
19
+ raise NotImplementedError(errMsg)
20
+
21
+ # --------------------------------------------------------------------
22
+ def GetPropertyIsNotImplemented(classType: type, methodName: str):
23
+ assert type(classType) == type
24
+ assert type(methodName) == str
25
+ assert methodName != ""
26
+
27
+ errMsg = "Get property {0}::{1} is not implemented.".format(
28
+ classType.__name__, methodName
29
+ )
30
+ raise NotImplementedError(errMsg)
31
+
32
+ # --------------------------------------------------------------------
33
+ def OptionNameIsNone():
34
+ errMsg = "Option name is None."
35
+ raise Exception(errMsg)
36
+
37
+ # --------------------------------------------------------------------
38
+ def OptionNameHasBadType(nameType: type):
39
+ assert nameType is not None
40
+ assert type(nameType) == type
41
+
42
+ errMsg = "Option name has nad type [{0}]".format(nameType.__name__)
43
+ raise Exception(errMsg)
44
+
45
+ # --------------------------------------------------------------------
46
+ def OptionNameIsEmpty():
47
+ errMsg = "Option name is empty."
48
+ raise Exception(errMsg)
49
+
50
+ # --------------------------------------------------------------------
51
+ def NoneValueIsNotSupported():
52
+ errMsg = "None value is not supported."
53
+ raise Exception(errMsg)
54
+
55
+ # --------------------------------------------------------------------
56
+ def NoneOptionValueItemIsNotSupported(optionName: str):
57
+ assert type(optionName) == str
58
+ assert optionName != ""
59
+
60
+ errMsg = "None value item of option [{0}] is not supported.".format(optionName)
61
+ raise Exception(errMsg)
62
+
63
+ # --------------------------------------------------------------------
64
+ def CommentObjectWasDeleted():
65
+ errMsg = "Comment object was deleted."
66
+ raise Exception(errMsg)
67
+
68
+ # --------------------------------------------------------------------
69
+ def OptionObjectWasDeleted():
70
+ errMsg = "Option object was deleted."
71
+ raise Exception(errMsg)
72
+
73
+ # --------------------------------------------------------------------
74
+ def IncludeObjectWasDeleted():
75
+ errMsg = "Include object was deleted."
76
+ raise Exception(errMsg)
77
+
78
+ # --------------------------------------------------------------------
79
+ def FileLineObjectWasDeleted():
80
+ errMsg = "FileLine object was deleted."
81
+ raise Exception(errMsg)
82
+
83
+ # --------------------------------------------------------------------
84
+ def FileObjectWasDeleted():
85
+ errMsg = "File object was deleted."
86
+ raise Exception(errMsg)
87
+
88
+ # --------------------------------------------------------------------
89
+ def BadOptionValueType(optionName: str, optionValueType: type, expectedType: type):
90
+ assert type(optionName) == str
91
+ assert type(optionValueType) == type
92
+ assert type(expectedType) == type
93
+
94
+ errMsg = "Bad option [{0}] value type [{1}]. Expected type is [{2}].".format(
95
+ optionName, optionValueType.__name__, expectedType.__name__
96
+ )
97
+ raise Exception(errMsg)
98
+
99
+ # --------------------------------------------------------------------
100
+ def CantConvertOptionValue(optionName: str, sourceType: type, targetType: type):
101
+ assert type(optionName) == str
102
+ assert type(sourceType) == type
103
+ assert type(targetType) == type
104
+
105
+ errMsg = (
106
+ "Can't convert option [{0}] value from type [{1}] to type [{2}].".format(
107
+ optionName, sourceType.__name__, targetType.__name__
108
+ )
109
+ )
110
+ raise Exception(errMsg)
111
+
112
+ # --------------------------------------------------------------------
113
+ def BadOptionValueItemType(
114
+ optionName: str, optionValueItemType: type, expectedType: type
115
+ ):
116
+ assert type(optionName) == str
117
+ assert type(optionValueItemType) == type
118
+ assert type(expectedType) == type
119
+
120
+ errMsg = (
121
+ "Bad option [{0}] value item type [{1}]. Expected type is [{2}].".format(
122
+ optionName, optionValueItemType.__name__, expectedType.__name__
123
+ )
124
+ )
125
+ raise Exception(errMsg)
126
+
127
+ # --------------------------------------------------------------------
128
+ def CommentTextContainsInvalidSymbols():
129
+ errMsg = "Comment text contains invalid symbols."
130
+ raise Exception(errMsg)
131
+
132
+ # --------------------------------------------------------------------
133
+ def FileIsAlreadyRegistered(file_path: str):
134
+ errMsg = "File [{0}] is already registered.".format(file_path)
135
+ raise Exception(errMsg)
136
+
137
+ # --------------------------------------------------------------------
138
+ def OptionIsAlreadyExistInThisFile(filePath: str, optionName: str):
139
+ assert type(filePath) == str
140
+ assert type(optionName) == str
141
+ assert filePath != ""
142
+ assert optionName != ""
143
+
144
+ errMsg = "Option [{0}] already exist in this file [{1}].".format(
145
+ optionName, filePath
146
+ )
147
+ raise Exception(errMsg)
148
+
149
+ # --------------------------------------------------------------------
150
+ def OptionIsAlreadyExistInAnotherFile(filePath: str, optionName: str):
151
+ assert type(filePath) == str
152
+ assert type(optionName) == str
153
+ assert filePath != ""
154
+ assert optionName != ""
155
+
156
+ errMsg = "Option [{0}] already exist in another file [{1}].".format(
157
+ optionName, filePath
158
+ )
159
+ raise Exception(errMsg)
160
+
161
+ # --------------------------------------------------------------------
162
+ def OptionIsAlreadyExistInFile(filePath: str, optionName: str):
163
+ assert type(filePath) == str
164
+ assert type(optionName) == str
165
+ assert filePath != ""
166
+ assert optionName != ""
167
+
168
+ errMsg = "Option [{0}] already exist in the file [{1}].".format(
169
+ optionName, filePath
170
+ )
171
+ raise Exception(errMsg)
172
+
173
+ # --------------------------------------------------------------------
174
+ def OptionValueItemIsAlreadyDefined(filePath: str, optName: str, valueItem: any):
175
+ assert type(filePath) == str
176
+ assert type(optName) == str
177
+
178
+ errMsg = "Another definition of option [{1}] value item [{2}] is found in the file [{0}].".format(
179
+ filePath, optName, valueItem
180
+ )
181
+ raise Exception(errMsg)
182
+
183
+ # --------------------------------------------------------------------
184
+ def OptionValueItemIsAlreadyDefinedInAnotherFile(
185
+ filePath: str, optName: str, valueItem: any
186
+ ):
187
+ assert type(filePath) == str
188
+ assert type(optName) == str
189
+
190
+ errMsg = "Definition of option [{1}] value item [{2}] is found in another file [{0}].".format(
191
+ filePath, optName, valueItem
192
+ )
193
+ raise Exception(errMsg)
194
+
195
+ # --------------------------------------------------------------------
196
+ def UnknownFileName(fileName: str):
197
+ assert type(fileName) == str
198
+
199
+ errMsg = "Unknown file name [{0}].".format(fileName)
200
+ raise Exception(errMsg)
201
+
202
+ # --------------------------------------------------------------------
203
+ def MultipleDefOfFileIsFound(fileName: str, count: int):
204
+ assert type(fileName) == str
205
+ assert type(count) == int
206
+
207
+ errMsg = "Multiple definitition of file [{0}] is found - {1}.".format(
208
+ fileName, count
209
+ )
210
+ raise Exception(errMsg)
211
+
212
+ # --------------------------------------------------------------------
213
+ def FilePathIsEmpty():
214
+ errMsg = "File path is empty."
215
+ raise Exception(errMsg)
216
+
217
+ # --------------------------------------------------------------------
218
+ def FileWasModifiedExternally(
219
+ filePath: str,
220
+ ourLastMDate: datetime.datetime,
221
+ curLastMDate: datetime.datetime,
222
+ ):
223
+ assert type(filePath) == str
224
+ assert type(ourLastMDate) == datetime.datetime
225
+ assert type(curLastMDate) == datetime.datetime
226
+
227
+ errMsg = "File [{0}] was modified externally. Our timestamp is [{1}]. The current file timestamp is [{2}].".format(
228
+ filePath, ourLastMDate, curLastMDate
229
+ )
230
+ raise Exception(errMsg)
231
+
232
+ # --------------------------------------------------------------------
233
+ def FileLineAlreadyHasComment():
234
+ errMsg = "File line already has a comment."
235
+ raise Exception(errMsg)
236
+
237
+ # --------------------------------------------------------------------
238
+ def FileLineAlreadyHasOption(optionName: str):
239
+ assert type(optionName) == str
240
+
241
+ errMsg = "File line already has the option [{0}].".format(optionName)
242
+ raise Exception(errMsg)
243
+
244
+ # --------------------------------------------------------------------
245
+ def FileLineAlreadyHasIncludeDirective():
246
+ errMsg = "File line already has an include directive."
247
+
248
+ raise Exception(errMsg)
249
+
250
+ # --------------------------------------------------------------------
251
+ def CfgReader__UnexpectedSymbol(lineNum: int, colNum: int, ch: str):
252
+ assert type(lineNum) == int
253
+ assert type(colNum) == int
254
+ assert type(ch) == str
255
+
256
+ errMsg = "Unexpected symbol in line {0}, column {1}: [{2}]".format(
257
+ lineNum, colNum, ch
258
+ )
259
+ raise Exception(errMsg)
260
+
261
+ # --------------------------------------------------------------------
262
+ def CfgReader__IncludeWithoutPath(lineNum: int):
263
+ assert type(lineNum) == int
264
+ assert lineNum >= 0
265
+
266
+ errMsg = "Include directive in line {0} does not have a path.".format(lineNum)
267
+ raise Exception(errMsg)
268
+
269
+ # --------------------------------------------------------------------
270
+ def CfgReader__EndOfIncludePathIsNotFound(lineNum: int):
271
+ assert type(lineNum) == int
272
+ assert lineNum >= 0
273
+
274
+ errMsg = "The end of an include path is not found. Line {0}.".format(lineNum)
275
+ raise Exception(errMsg)
276
+
277
+ # --------------------------------------------------------------------
278
+ def CfgReader__IncompletedEscapeInInclude(lineNum: int):
279
+ assert type(lineNum) == int
280
+ assert lineNum >= 0
281
+
282
+ errMsg = "Escape in an include path is not completed. Line {0}.".format(lineNum)
283
+ raise Exception(errMsg)
284
+
285
+ # --------------------------------------------------------------------
286
+ def CfgReader__UnknownEscapedSymbolInInclude(lineNum: int, colNum: int, ch: str):
287
+ assert type(lineNum) == int
288
+ assert type(colNum) == int
289
+ assert type(ch) == str
290
+ assert lineNum >= 0
291
+ assert colNum >= 0
292
+ assert ch != ""
293
+
294
+ errMsg = "Unknown escape symbol [{2}] in an include path. Line {0}. Column {1}.".format(
295
+ lineNum, colNum, ch
296
+ )
297
+ raise Exception(errMsg)
298
+
299
+ # --------------------------------------------------------------------
300
+ def CfgReader__IncludeHasEmptyPath(lineNum: int):
301
+ assert type(lineNum) == int
302
+ assert lineNum >= 0
303
+
304
+ errMsg = "Include in line {0} has an empty path.".format(lineNum)
305
+ raise Exception(errMsg)
306
+
307
+ # --------------------------------------------------------------------
308
+ def CfgReader__OptionWithoutValue(optionName: str, lineNum: int):
309
+ assert type(lineNum) == int
310
+ assert type(optionName) == str
311
+ assert lineNum >= 0
312
+ assert optionName != ""
313
+
314
+ errMsg = "Option [{0}] in line {1} does not have a value.".format(
315
+ optionName, lineNum
316
+ )
317
+ raise Exception(errMsg)
318
+
319
+ # --------------------------------------------------------------------
320
+ def CfgReader__EndQuotedOptionValueIsNotFound(optionName: str, lineNum: int):
321
+ assert type(lineNum) == int
322
+ assert type(optionName) == str
323
+ assert lineNum >= 0
324
+ assert optionName != ""
325
+
326
+ errMsg = "Value of quoted option [{0}] is not completed. Line {1}.".format(
327
+ optionName, lineNum
328
+ )
329
+ raise Exception(errMsg)
330
+
331
+ # --------------------------------------------------------------------
332
+ def CfgReader__IncompletedEscapeInQuotedOptionValue(optionName: str, lineNum: int):
333
+ assert type(lineNum) == int
334
+ assert type(optionName) == str
335
+ assert lineNum >= 0
336
+ assert optionName != ""
337
+
338
+ errMsg = "Escape in a value of quoted option [{0}] is not completed. Line {1}.".format(
339
+ optionName, lineNum
340
+ )
341
+ raise Exception(errMsg)
342
+
343
+ # --------------------------------------------------------------------
344
+ def CfgReader__UnknownEscapedSymbolInQuotedOptionValue(
345
+ optionName: str, lineNum: int, colNum: int, ch: str
346
+ ):
347
+ assert type(lineNum) == int
348
+ assert type(optionName) == str
349
+ assert type(ch) == str
350
+ assert lineNum >= 0
351
+ assert optionName != ""
352
+ assert ch != ""
353
+
354
+ errMsg = "Unknown escape symbol [{3}] in a value of quoted option [{0}]. Line {1}. Column {2}.".format(
355
+ optionName, lineNum, colNum, ch
356
+ )
357
+ raise Exception(errMsg)
358
+
359
+ # --------------------------------------------------------------------
360
+ def BadFormatOfCommaSeparatedList():
361
+ errMsg = "Bad format of comma separated list."
362
+ raise Exception(errMsg)
363
+
364
+
365
+ # //////////////////////////////////////////////////////////////////////////////
@@ -0,0 +1,308 @@
1
+ # //////////////////////////////////////////////////////////////////////////////
2
+ # Postgres Pro. PostgreSQL Configuration Python Library.
3
+
4
+ from __future__ import annotations
5
+
6
+ from .raise_error import RaiseError
7
+
8
+ import typing
9
+
10
+ # //////////////////////////////////////////////////////////////////////////////
11
+ # class LineReader
12
+
13
+
14
+ class LineReader:
15
+ C_DEFAULT_TAB_SIZE = 4
16
+
17
+ m_TabSize: int
18
+
19
+ m_LineNum: int
20
+ m_ColNum: int
21
+ m_Next: int
22
+ m_Data: str
23
+
24
+ # --------------------------------------------------------------------
25
+ def __init__(self, tabSize=C_DEFAULT_TAB_SIZE):
26
+ assert type(tabSize) == int
27
+ assert tabSize > 0
28
+
29
+ self.m_TabSize = tabSize
30
+
31
+ self.m_LineNum = 0
32
+ self.m_ColNum = 0
33
+ self.m_Next = 0
34
+ self.m_Data = 0
35
+
36
+ # --------------------------------------------------------------------
37
+ def SetData(self, lineData: str):
38
+ assert type(lineData) == str
39
+ assert type(self.m_LineNum) == int
40
+ assert self.m_LineNum >= 0
41
+
42
+ self.m_Data = lineData
43
+ self.m_LineNum += 1
44
+ self.m_ColNum = 0
45
+ self.m_Next = 0
46
+
47
+ # --------------------------------------------------------------------
48
+ def GetLineNum(self) -> int:
49
+ assert type(self.m_LineNum) == int
50
+ assert self.m_LineNum >= 0
51
+ return self.m_LineNum
52
+
53
+ # --------------------------------------------------------------------
54
+ def GetColNum(self) -> int:
55
+ assert type(self.m_ColNum) == int
56
+ assert self.m_ColNum >= 0
57
+ return self.m_ColNum
58
+
59
+ # --------------------------------------------------------------------
60
+ def GetColOffset(self) -> int:
61
+ assert type(self.m_ColNum) == int
62
+ assert self.m_ColNum > 0
63
+ return self.m_ColNum - 1
64
+
65
+ # --------------------------------------------------------------------
66
+ def StepBack(self):
67
+ assert type(self.m_Next) == int
68
+ assert type(self.m_ColNum) == int
69
+ assert type(self.m_Data) == str
70
+ assert self.m_Next > 0
71
+ assert self.m_Next <= len(self.m_Data)
72
+ assert self.m_ColNum > 0
73
+
74
+ self.m_Next -= 1
75
+
76
+ if self.m_Next == 0:
77
+ assert self.m_ColNum == 1
78
+ self.m_ColNum = 0
79
+ else:
80
+ assert self.m_Next > 0
81
+ stepSize = self.Helper__GetStepSize(self.m_Data[self.m_Next - 1])
82
+ assert self.m_ColNum > stepSize
83
+ self.m_ColNum -= stepSize
84
+ assert self.m_ColNum > 0
85
+
86
+ # --------------------------------------------------------------------
87
+ def ReadSymbol(self) -> typing.Optional[str]:
88
+ assert type(self.m_Next) == int
89
+ assert type(self.m_ColNum) == int
90
+ assert type(self.m_Data) == str
91
+ assert self.m_Next >= 0
92
+ assert self.m_Next <= len(self.m_Data)
93
+
94
+ if self.m_Next == len(self.m_Data):
95
+ return None
96
+
97
+ result = self.m_Data[self.m_Next]
98
+
99
+ if self.m_Next == 0:
100
+ self.m_ColNum = 1
101
+ else:
102
+ self.m_ColNum += self.Helper__GetStepSize(self.m_Data[self.m_Next - 1])
103
+
104
+ self.m_Next += 1
105
+
106
+ return result
107
+
108
+ # --------------------------------------------------------------------
109
+ def Helper__GetStepSize(self, ch: str) -> int:
110
+ assert type(ch) == str
111
+ assert ch != ""
112
+ assert type(self.m_TabSize) == int
113
+ assert self.m_TabSize > 0
114
+
115
+ if ch == "\t":
116
+ return self.m_TabSize
117
+
118
+ return 1
119
+
120
+
121
+ # //////////////////////////////////////////////////////////////////////////////
122
+ # class ReadUtils
123
+
124
+
125
+ class ReadUtils:
126
+ def IsSpace(ch: str) -> bool:
127
+ assert type(ch) == str
128
+
129
+ if ch == " ":
130
+ return True
131
+
132
+ if ch == "\t":
133
+ return True
134
+
135
+ return False
136
+
137
+ # --------------------------------------------------------------------
138
+ def IsEOL(ch: str) -> bool:
139
+ assert type(ch) == str
140
+
141
+ if ch == "\n":
142
+ return True
143
+
144
+ return False
145
+
146
+ # --------------------------------------------------------------------
147
+ def IsValidSeqCh1(ch: str) -> bool:
148
+ assert type(ch) == str
149
+
150
+ if ch.isalpha():
151
+ return True
152
+
153
+ if ch in "_":
154
+ return True
155
+
156
+ return False
157
+
158
+ # --------------------------------------------------------------------
159
+ def IsValidSeqCh2(ch: str) -> bool:
160
+ assert type(ch) == str
161
+
162
+ if ch.isdigit():
163
+ return True
164
+
165
+ return __class__.IsValidSeqCh1(ch)
166
+
167
+ # --------------------------------------------------------------------
168
+ def Unpack_StrList2(source: str) -> typing.List[str]:
169
+ assert source is not None
170
+ assert type(source) == str
171
+
172
+ C_MODE__NONE = 0
173
+ C_MODE__QSTART = 1
174
+ C_MODE__QEND = 2
175
+
176
+ class tagCtx:
177
+ mode: int
178
+ curValueItem: typing.Optional[str]
179
+ dataLength: int
180
+ result: list[str]
181
+ index: set[str]
182
+
183
+ ctx = tagCtx()
184
+ ctx.mode = C_MODE__NONE
185
+ ctx.curValueItem = None
186
+ ctx.dataLength = 0
187
+ ctx.result = list()
188
+ ctx.index = set()
189
+
190
+ i = 0
191
+ length = len(source)
192
+
193
+ # ----------------------------------------------
194
+ def LOCAL__append_to_curValueItem(ctx: tagCtx, ch: str, isData: bool):
195
+ assert type(ctx) == tagCtx
196
+ assert type(ch) == str
197
+ assert len(ch) == 1
198
+ assert type(isData) == bool
199
+
200
+ if ctx.curValueItem is None:
201
+ ctx.curValueItem = ch
202
+ else:
203
+ assert type(ctx.curValueItem) == str
204
+ ctx.curValueItem += ch
205
+
206
+ if isData:
207
+ ctx.dataLength = len(ctx.curValueItem)
208
+
209
+ return
210
+
211
+ # ----------------------------------------------
212
+ def LOCAL__append_curValueItem_to_result(ctx: tagCtx, isLast: bool):
213
+ assert type(ctx) == tagCtx
214
+
215
+ if ctx.mode == C_MODE__QSTART:
216
+ # quoted item is not completed
217
+ RaiseError.BadFormatOfCommaSeparatedList()
218
+
219
+ if ctx.curValueItem is None:
220
+ if isLast and ctx.mode == C_MODE__NONE:
221
+ return
222
+ s = ""
223
+ elif ctx.mode == C_MODE__QEND:
224
+ s = ctx.curValueItem
225
+ else:
226
+ assert ctx.mode == C_MODE__NONE
227
+ s = ctx.curValueItem[: ctx.dataLength]
228
+
229
+ if s not in ctx.index:
230
+ ctx.index.add(s)
231
+ ctx.result.append(s)
232
+
233
+ ctx.mode = C_MODE__NONE
234
+ ctx.curValueItem = ""
235
+ ctx.dataLength = 0
236
+ return
237
+
238
+ # ----------------------------------------------
239
+ while True:
240
+ assert i >= 0
241
+ assert i <= length
242
+
243
+ if i == length:
244
+ LOCAL__append_curValueItem_to_result(ctx, True)
245
+ return ctx.result # GO HOME!
246
+
247
+ assert i >= 0
248
+ assert i < length
249
+
250
+ ch = source[i]
251
+
252
+ if ch == "," and ctx.mode != C_MODE__QSTART:
253
+ LOCAL__append_curValueItem_to_result(ctx, False)
254
+ i += 1
255
+ continue
256
+
257
+ # space
258
+ if not __class__.IsSpace(ch):
259
+ pass
260
+ else:
261
+ if ctx.mode == C_MODE__QEND:
262
+ i += 1
263
+ continue
264
+
265
+ if ctx.mode == C_MODE__QSTART:
266
+ pass
267
+ elif ctx.curValueItem is None or ctx.curValueItem == "":
268
+ i += 1
269
+ continue
270
+
271
+ # append this RAW space to result
272
+ LOCAL__append_to_curValueItem(ctx, ch, False)
273
+ i += 1
274
+ continue
275
+
276
+ assert not __class__.IsSpace(ch)
277
+
278
+ if ch == '"':
279
+ # quoted item
280
+ if ctx.mode == C_MODE__NONE:
281
+ ctx.mode = C_MODE__QSTART
282
+ i += 1
283
+ continue
284
+
285
+ if ctx.mode == C_MODE__QSTART:
286
+ i += 1
287
+
288
+ if i != length and source[i] == '"':
289
+ LOCAL__append_to_curValueItem(ctx, '"', True)
290
+ i += 1
291
+ continue
292
+
293
+ ctx.mode = C_MODE__QEND
294
+ continue
295
+
296
+ assert ctx.mode == C_MODE__QEND
297
+ RaiseError.BadFormatOfCommaSeparatedList()
298
+
299
+ if ctx.mode == C_MODE__QEND:
300
+ # Data after quoted text
301
+ RaiseError.BadFormatOfCommaSeparatedList()
302
+
303
+ LOCAL__append_to_curValueItem(ctx, ch, True)
304
+ i += 1
305
+ continue
306
+
307
+
308
+ # //////////////////////////////////////////////////////////////////////////////