Package yapydata ::
Package datatree ::
Module synini
1
2 """The *YapyData.ini* module provides the extended *INI* file syntax access
3 with optional extended syntax features.
4 The core syntax is defined by the standard library *configparser.ConfigParser*,
5 *YapyData.data* supports *Python2.7*, and *Python3.5+*.
6
7 """
8
9 from __future__ import absolute_import
10
11 import os
12 import sys
13 import re
14
15 import itertools
16
17 from pythonids import PYV35Plus, ISSTR
18 from sourceinfo.fileinfo import getcaller_filename, getcaller_linenumber
19
20
21 if PYV35Plus:
22 import configparser
23 else:
24
25
26
27
28
29 import configparser
30
31
32 try:
33 from ConfigParser import ConfigParser
34 except:
35 from configparser import ConfigParser
36
37
38 from collections import OrderedDict
39
40 import yapydata
41 from yapydata.datatree import YapyDataTreeError
42 from yapydata.datatree.datatree import DataTree, YapyDataDataTreeOidError
43
44
45 __author__ = 'Arno-Can Uestuensoez'
46 __license__ = "Artistic-License-2.0 + Forced-Fairplay-Constraints"
47 __copyright__ = "Copyright (C) 2019 Arno-Can Uestuensoez" \
48 " @Ingenieurbuero Arno-Can Uestuensoez"
49 __version__ = '0.1.1'
50 __uuid__ = "60cac28d-efe6-4a8d-802f-fa4fc94fa741"
51
52 __docformat__ = "restructuredtext en"
56 """Generic INI syntax error.
57 """
58 pass
59
60
61
62 _KEYWORDS = {'true':True, 'false': False, 'null':None,}
63
64
65
66
67
68 _C_LIST = 1
69 _C_DICT = 2
70
71 _C_BYTEARRAY = 4
72 _C_TUPLE = 8
73 _C_SET = 16
74
75
76
77 _CONTAINERS = {
78 'default': _C_LIST,
79 '': _C_LIST,
80 'list': _C_LIST,
81 'dict': _C_DICT,
82 }
83
84
85
86
87
88
89
90
91 _CONTAINERSX = {
92 'bytearray': _C_BYTEARRAY,
93 'tuple': _C_TUPLE,
94 'set': _C_SET,
95 }
96
97
98
99
100 _CONCAT_LIST=re.compile(r'\r{0,1}\n[ \t]*,')
101
102
103 _CONCAT_PATH=re.compile(r'\r{0,1}\n[ \t]*[:]')
104
105
106 _CLEAR_KEY=re.compile(r'^[ \t]*(.*?)[ \t]*$')
110 """Creates a new branch including the assigned value to
111 the last node. The node types are defined by the types
112 of the *subpath* entries.
113
114 Supports a single linear branch only, no sub-branching.
115
116 The created path is validated for permitted types.
117 The derived types such as JSON have to support their
118 own branch method. Thus provided as a static method.
119
120 Args:
121 subpath:
122 Variable list/tuple of path keys and indexes.
123
124 kargs:
125 value:
126 Value to be assigned to the final node.
127
128 Returns:
129 A created branch.
130
131 Raises:
132 pass-through
133
134 """
135 _val = kargs.get('value')
136 _subpath=list(subpath)
137 try:
138 ik = _subpath.pop(0)
139 except IndexError:
140 return _val
141
142 if isinstance(ik, int):
143 if ik != 0:
144
145 raise YapyDataDataTreeOidError(
146 "new list requires idx==0: %s\n see: %s\n" %(
147 str(subpath),
148 str(ik)
149 )
150 )
151 return [grow_branch(*_subpath, value=_val)]
152
153 elif isinstance(ik, ISSTR) or ik in (True, False, None,):
154
155 return {ik: grow_branch(*_subpath, value=_val)}
156
157 elif isinstance(ik, frozenset):
158
159 return {ik: grow_branch(*_subpath, value=_val)}
160
161 raise YapyDataDataTreeOidError(
162 "invalid subpath key/index: %s\n see: %s\n" %(
163 str(subpath),
164 str(ik)
165 )
166 )
167
170 """Scan tree into JSON representation. Uses recursive calls to
171 readout_data through the logical tree spanned by *ConfigParser*.
172
173 Args:
174 xval:
175 The loaded input tree as received from *ConfigDataINIX*,
176 which is defined by *ConfigParser.read_file()*.
177
178 For example a node *cf*::
179
180 datafile = os.path.abspath(fpname)
181 cf = ConfigDataINIX(datafile)
182 cf.load_parser()
183 cf.import_data(datafile)
184
185 is read out as ::
186
187 datatree = readout_data(cf)
188
189
190 Returns:
191 The resulting scanned data structure.
192
193 Raises:
194 pass-through
195
196 """
197 return xval.readout_data()
198
201 """Add lists for multi-key items.
202 """
204 """Intercept keys which are already present.
205 """
206 if key in self:
207 if isinstance(value, list):
208 if isinstance(self[key], list):
209 try:
210 self[key].extend(value)
211 except KeyError:
212 self[key] = value
213 else:
214 self.__dict__[key] = value
215 return
216
217
218 super(MultiOrderedDict, self).__setitem__(key, value)
219
222 """Preserves case of all keys - including DEFAULT section.
223 Suppress formatting of *optionstr*, preserves upper case characters.
224 """
227
230 """The the supported in-memory data tree representation of the *INI* syntax
231 supports a JSON compatible in memory data structure. The supported structure
232 relies on the standard *ConfigParser* - of *Python2* and *Python3* - with a
233 minimum set of custom addons. For a full set of extensions refer to the
234 package *multiconf*.
235
236 The basic scheme of the stored syntax is::
237
238 ini-for-in-memory-json := {
239 <sections>
240 }
241 sections := <section> [, <sections>]
242 section := <section-attributes>
243 section-attributes := <attr-value-pairs> [, <section-attributes>]
244 attr-value-pairs := <attr-value-pair> [, <attr-value-pairs>]
245 attr-value-pair := <attr-name> <separator> <attr-value>
246 attr-name := "any valid ConfigParser string compatible to a JSON string"
247 attr-value := (
248 <integer> | <integer-as-string>
249 | <float> | <float-as-string>
250 | <string>
251 | <list>
252 | <dict>
253 | <boolean> | <boolean-as-string>
254 | <null> | <null-as-string>
255 )
256
257 integer-as-string := '"' <integer> '"' # treated as string
258 integer := "any non-quoted valid integer value" # treated as integer
259 float-as-string := '"' <float> '"' # treated as string
260 float := "any non-quoted valid integer value" # treated as float
261 string := "any valid string"
262 boolean := (true | false)
263 boolean-as-string := '"' <boolean> '"' # treated as string
264 null := null
265 null-as-string := '"' <null> '"' # treated as string
266 separator := ( ':' | '=' )
267
268 The following derived proprietary container types are provided. These are
269 compatible with the basic representation of the higher layer *multiconf*
270 package, which also provides command line compilation and cross-conversion
271 utilies.
272
273 The *list* entries are represented as multiple lines of entries with leading
274 white-spaces and a comma. ::
275
276 list := <proprietary-basic-multiline-list-syntax>
277 proprietary-basic-multiline-list-syntax := <attr-name> <separator> <list-item> <CR> <list-items-multiline> <CR>
278 list-items-multiline := <ws> ',' <list-item> <CR> [<list-items-multiline>]
279 list-item := attr-value
280 ws := "arbitrary whitespace - <SPACE>, <tab>"
281 CR := "new line"
282
283 The *dict* entries are represented as multiple lines of entries with leading
284 white-spaces and a comma::
285
286 dict := <proprietary-basic-multiline-dict-syntax>
287 proprietary-basic-multiline-dict-syntax := <attr-name> <separator> <attr-dict-item> <CR> <dict-items-multiline> <CR>
288 dict-items-multiline := <ws> ',' <dict-item> <CR> [<dict-items-multiline>]
289 dict-item := attr-value-pair
290 ws := "arbitrary whitespace - <SPACE>, <tab>"
291 CR := "new line"
292
293 The data tree is compatible with the standard packas *json*.
294
295 """
296
297 @staticmethod
299 """Validate compliance of top-node.
300 """
301 if not isinstance(value, (dict, list, )):
302 raise YapyDataINIError(
303 "top 'node' must be a valid INI type for RFC-4627 processing: (dict, list), got: "
304 + str(type(value))
305 )
306 return
307
309 """
310 Args:
311 data:
312 A JSON compliant in-memory data tree in accordance to RFC-7159::
313
314 json-value := (
315 object | array
316 | number
317 | string
318 | false | true
319 | null
320 )
321
322 The equivalent *Python* types are - based on JSON-RFC7159 as canonical in-memory data::
323
324 RFC-7159-type-for-json := (
325 dict | list # see: object, array
326 | int | float # see: number
327 | str # see: unicode / for Python: ISSTR = (str(3) | unicode(2))
328 | None | True | False # see: null, true, false
329 )
330
331 The initial data defines the permitted type of the first item
332 within the *subpath* of the spanned data tree.
333
334 Thus atomic data types define a single node data tree only - new in RFC-7159.
335
336 kargs:
337 syntax:
338 Defines the syntax variant::
339
340 syntax := (
341 'base' # base core syntax for multi-syntax environments with global types
342 | 'ext' # extended syntax with specific extension for this module
343 | 'auto' # for now enables all choices - basically the same as 'ext'
344 )
345
346 default := 'base' # maximum compatibility for multi-syntax environments
347
348 Returns:
349 None / initialized object
350
351 Raises:
352 YapyDataDataTreeError
353
354 pass-through
355
356 """
357
358 _syn = kargs.get('syntax')
359 if _syn in ('ext', 'auto',):
360
361 global _CONTAINERS
362 _CONTAINERS.update(_CONTAINERSX)
363
364
365 DataTreeINI.isvalid_top(data, **kargs)
366
367
368
369 super(DataTreeINI, self).__init__(data)
370
372 """Validates types of own data attributes.
373
374 Args:
375 name:
376 Name of the attribute. Following are reserved and
377 treated special:
378
379 * type: str - 'data'
380 The value is treated as the replacement of the internal
381 data attribute. Replaces or creates the complete data
382 of teh current instance.
383
384 value:
385 The value of the attribute. This by default superposes
386 present values by replacement. Non-present are created.
387
388 Returns:
389
390 Raises:
391 YapyDataINIError
392
393 """
394 if name == 'data':
395
396
397
398 DataTreeINI.isvalid_top(value)
399 self.__dict__[name] = value
400
401 else:
402
403
404
405 return object.__setattr__(self, name, value)
406
407 - def import_data(self, fpname, key=None, node=None, **kargs):
408 """Reads an INI file. This is a simple basic method for the application
409 on the lower layers of the software stack. It is designed for minimal
410 dependencies. The used library is the standard *configparser* package.
411
412 Args:
413 fpname:
414 File path name of the *INI* file. ::
415
416 fpname := <ini-file-path-name>
417 ini-file-path-name := (
418 <file-path-name> # with extension
419 | <file-path-name> '.ini' # without extension, for multiple syntaxes
420 )
421
422 key:
423 The key for the insertion point::
424
425 node[key] = <file-data>
426
427 default := None - replace self.data,
428
429 The caller is responsible for the containment of the provided
430 node within the data structure represented by this object. No
431 checks are performed.
432
433 node:
434 The node for the insertion of the read data.::
435
436 default := <top>
437
438 Returns:
439 Reference to read data structure.
440
441 Raises:
442 YapyDataConfigError
443
444 pass-through
445
446 """
447 if not os.path.isfile(fpname):
448 if not os.path.isfile(fpname + '.ini'):
449 raise YapyDataINIError("Missing file: " + str(fpname))
450 else:
451 fpname = fpname + '.ini'
452
453 datafile = os.path.abspath(fpname)
454 cf = ConfigDataINIX(datafile)
455 cf.load_parser()
456 cf.import_data(datafile)
457
458 jval = cf.readout_data()
459
460 if key and node == None:
461 raise YapyDataINIError("Given key(%s) requires a valid node." % (str(key)))
462
463 if key:
464 node[key] = jval
465 else:
466 self.data = jval
467
468 return jval
469
472 """A simple configuration file parser based on the standard *ConfigParser* class.
473
474 The final resulting data with completely applied syntax-extensions is available by
475 the method *readout_data()*.
476
477 Supports the data types::
478
479 int, float, str
480
481 multi-line lists,
482 multi-line search-paths
483
484 null
485 true, false
486
487 The optional structure::
488
489 global-attributes-without-section
490
491 The standard file extensions are::
492
493 '.ini'
494
495 The supported stnadard features of *ConfigParser* include::
496
497 interpolation
498
499 For detailed information refer to the parameters of the *__init__* method.
500 """
501
502 suffixes = ('ini', )
503
504
506 """
507 Args:
508 **conf**:
509 The file path name of the configuration file.
510
511 kargs:
512 For additional parameters see *ConfigData*.
513
514 allow_no_value:
515 Enables the support for keys without values
516 of *INI* format files. Supported by the standard
517 library based *configparser* . The value
518 could be applied to derived custom parser::
519
520 default := False
521
522 See parameter *allow_no_value* of
523 *configparser.ConfigParser*.
524
525 casesens:
526 Preserves case of keys::
527
528 default := False
529
530 comment_prefixes:
531 Defines the comment prefixes::
532
533 default := ('#', ';')
534
535 delimiters:
536 Defines the delimiters for *INI* format based
537 files. Supported by the standard library based
538 *configparser* . The value could be applied to
539 derived custom parser::
540
541 default := ('=', ':',)
542
543 dict_type:
544 The type of dictionary to be used by the parent class::
545
546 default := None
547
548 empty_lines_in_values::
549
550 default := False
551
552 inline_comment_prefixes:
553 Defines the inline comment prefixes::
554
555 default := None
556
557 interpolation:
558 Enables the creation and replacement of variables
559 within configuration files. Depends on the derived
560 class, when not supported simply ignored::
561
562 default := True
563
564 See parameter *interpolation* of
565 *configparser.ConfigParser*.
566
567 sectionpaths:
568 Enables the conversion and interpretation of section names
569 as path entries. This is required, when the versatility
570 of the converted and/or merged syntaxes are of different degree,
571 and the actual used syntax data path elements could not be
572 converted. In this case an intermediate sub-syntax is supported
573 by a dotted path notation, which could be converted between the
574 applied syntaxes::
575
576 sectionpaths := (
577 True # long data paths e.g. from *JSON* are
578 # converted to dotted section names
579 # and vice versa
580 | False # requires compatible versatility,
581 # else raises exception
582 )
583
584 default := True
585
586
587 sectionpaths=True:
588 The section names of the native *INIX* syntax by default
589 constitute a one-level-only depth of data structures for
590 the complexity of structure definition.
591
592 sectionpaths=False:
593
594
595 sectionpathsep:
596 Defines the character used in section names as path separator.
597 The character has to be valid as provided by the config parser of the syntax,
598 in particular a valid character for section names of *INI* files, and has
599 to be semantically suitable as a special separator character::
600
601 sectionpathsep := []
602
603 default := '.'
604
605 Valid only when *sectionpaths* is active.
606
607 strict:
608 Controls the verification of duplicate sections
609 when these are used::
610
611 strict := (
612 True # raise an exception for duplicates
613 | False # accept
614 )
615
616 default := False
617
618 See *strict* option of *ConfigParser*.
619
620 quiet:
621 Suppresses display of non-errors::
622
623 default := False
624
625 Returns:
626 None/object
627
628 Raises:
629 pass-through
630
631 """
632 self.allow_no_value = kargs.get('allow_no_value', False)
633 self.casesens = kargs.get('casesens', False)
634 self.comment_prefixes = kargs.get('comment_prefixes', ('#', ';'))
635 self.delimiters = kargs.get('delimiters', ('=', ':',))
636 self.dict_type = kargs.get('dict_type', None)
637 self.empty_lines_in_values = kargs.get('empty_lines_in_values', False)
638 self.inline_comment_prefixes = kargs.get('inline_comment_prefixes', None)
639 self.interpolation = kargs.get('interpolation', True)
640 self.quiet = kargs.get('quiet', False)
641 self.strict = kargs.get('strict', False)
642
644 try:
645 return len(self.confdata.sections()) > 0
646 except Exception:
647 return False
648
650 try:
651 return len(self.confdata.sections()) > 0
652 except Exception:
653 return False
654
656 """Get the section object.
657 Requires for Python2 the backport from Python3 "configparser", see PyPI
658 """
659 return self.confdata[key]
660
661 - def get(self, key):
662 """Get the section object - compatible to Python3 and
663 the backport of the *configparser*.
664 """
665 if key in self.confdata.sections():
666 return self.confdata[key]
667 return None
668
670 """Reads the configuration file and imports data. Supported standard types are::
671
672 'cfg', 'conf', 'ini',
673
674 The imported data for the suported standard syntax is interpreted as:
675
676 +----------------------------------------+-------------+-------------------+-------------+-------------------------+----------------------------------------------+
677 | syntax of imported config | sections as | keys as | path as | insertion position | remark |
678 +========================================+=============+===================+=============+=========================+==============================================+
679 | `conf <parser_conf.html>`_ | sections | keys to <section> | -- | top, <section>, DEFAULT | no rename and no nested sections, no globals |
680 +----------------------------------------+-------------+-------------------+-------------+-------------------------+----------------------------------------------+
681 | `ini <parser_ini.html>`_ | sections | keys by section | -- | top, <section>, DEFAULT | no rename and no nested sections, no globals |
682 +----------------------------------------+-------------+-------------------+-------------+-------------------------+----------------------------------------------+
683 | `inix <parser_inix.html>`_ | sections | keys by section | -- | top, <section>, DEFAULT | no rename and no nested sections, no globals |
684 +----------------------------------------+-------------+-------------------+-------------+-------------------------+----------------------------------------------+
685
686 Args:
687 conf:
688 The file path name of the configuration file.
689
690 kargs:
691 Unknown options are passed through to the
692 configuration parser.
693
694 anchor:
695 The insertion point for the imported data::
696
697 anchor := (
698 <section>
699 | 'DEFAULT'
700 | <top>
701 )
702
703 top := "imports valid INIX/INI/CONF files with sections only"
704 section := "the name of the section"
705 'DEFAULT' := "keyword defined by the standard library as
706 global defaults for interpolation"
707
708 default := <top>
709
710 strict:
711 Activates validation. The boolean value is
712 mapped to the corresponding option of the
713 called import parser:
714
715 +------------+----------+-------+--------+
716 | parser | option | True | False |
717 +============+==========+=======+========+
718 | conf | strict | True | False |
719 +------------+----------+-------+--------+
720 | ini | strict | True | False |
721 +------------+----------+-------+--------+
722 | inix | strict | True | False |
723 +------------+----------+-------+--------+
724
725 syntax:
726 Force the provided syntax. For available
727 values refer to syntax multiplexer
728 *self.synmux*.
729
730 Returns:
731 True for success, else False or raises an exception.
732
733 Raises:
734 pass-through
735
736 """
737
738
739
740
741 with open(conf) as fp:
742 self.confdata.read_file(
743 itertools.chain(['[globaldummy]'], fp),
744 source=os.path.dirname(conf)
745 )
746 return self.confdata != []
747
748
750 return self.confdata.sections()
751
753 """Loads the syntax parser *configparser.ConfigParser* and
754 patches the behaviour for common 'conf' and 'cfg' format.
755 Supports the most of the files in '/etc' of POSIX based
756 OS.
757
758 Args:
759 kargs:
760 For the description of the options refer to the
761 method header of *multiconf.data.load_parser()*.
762 Unknown are passed through to the loaded
763 configuration parser.
764
765 For the following parameters see __init__:
766
767 * **allow_no_value**
768 * **casesens**
769 * **comment_prefixes**
770 * **inline_comment_prefixes**
771 * **delimiters**
772 * **dict_type**
773 * **empty_lines_in_values**
774 * **interpolation**
775 * **strict**
776 * **quiet**
777
778 Returns:
779 True, or raises an exception.
780
781 Raises:
782 pass-through
783
784 """
785 kw_optparser = {}
786
787 try:
788 kw_optparser['strict'] = kargs.pop('strict')
789 except:
790
791
792
793
794 pass
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852 _cs = True
853 if _cs:
854 _parser = CaseSensitiveConfigParser
855 else:
856 _parser = configparser.ConfigParser
857
858 if yapydata._debug > 1:
859 sys.stderr.write(
860 "DBG:%s:%s:_parser = %s\n" %(
861 str(getcaller_filename()),
862 str(getcaller_linenumber()),
863 str(_parser)
864 )
865 )
866 sys.stderr.write(
867 "DBG:%s:%s:kw_optparser = %s\n" %(
868 str(getcaller_filename()),
869 str(getcaller_linenumber()),
870 str(kw_optparser)
871 )
872 )
873
874
875
876
877
878
879
880
881
882
883
884
885 self.confdata = _parser(
886 **kw_optparser
887 )
888
889 return True
890
892 """Returns the configuration as JSON compatible format.
893 Removes the special dummy section header 'globaldummy',
894 see *import_data*.
895
896 Args:
897 kargs:
898 stronly:
899 Scans all as *str* only. ::
900
901 stronly := (
902 True # int and float are
903 # converted to str
904 | False # numeric values are kept
905 )
906
907 default := False
908
909 Returns:
910 In-memory JSON compatible data.
911
912 Raises:
913 pass-through
914
915 """
916 if self.confdata == None:
917 return
918 elif not self.confdata:
919 return str(self.confdata)
920
921 _stronly = kargs.get('stronly', False)
922
923 res = {}
924 for s in self.confdata.sections():
925 if s == 'globaldummy':
926 for k, v, in self.confdata.items(s):
927 if _stronly:
928 res[k] = v
929 continue
930
931 try:
932
933 res[k] = int(v)
934 except (ValueError, TypeError):
935 try:
936
937 res[k] = float(v)
938 except (ValueError, TypeError):
939 try:
940
941 res[k] = _KEYWORDS[v]
942 except KeyError:
943
944
945
946
947
948 try:
949 _v = _CONCAT_LIST.split(v)
950 if len(_v) > 1:
951
952
953
954 try:
955 container = _CONTAINERS[_v[0]]
956 _v.pop(0)
957 except KeyError:
958 container = _C_LIST
959
960 if container == _C_DICT:
961
962 res[k] = {}
963 for _vi in _v:
964 _dk,_dv = re.split(r'[=:]', _vi, 1)
965 _dk = str(_CLEAR_KEY.sub(r'\1', _dk))
966 try:
967 res[k][_dk] = int(_dv)
968 except (ValueError, TypeError):
969 try:
970 res[_dk] = float(_dv)
971 except (ValueError, TypeError):
972 res[_dk] = _dv
973
974 elif container == _C_BYTEARRAY:
975
976
977 res[k] = bytearray()
978 for _vi in _v:
979 try:
980 res[k].append(int(_vi))
981 except ValueError:
982
983 raise YapyDataTreeError(
984 "Bytearray(0..256) failed: [%s] = %s" %(
985 str(k),
986 str(_vi),
987 )
988 )
989
990 else:
991
992 res[k] = []
993 for _vi in _v:
994 try:
995 res[k].append(int(_vi))
996 except (ValueError, TypeError):
997 try:
998 res[k].append(float(_vi))
999 except (ValueError, TypeError):
1000 res[k].append(_vi)
1001
1002
1003 if container == _C_TUPLE:
1004 res[k] = tuple(res[k])
1005 elif container == _C_SET:
1006 res[k] = set(res[k])
1007
1008 else:
1009 res[k] = v
1010
1011 except TypeError:
1012 res[k] = v
1013
1014 else:
1015 res[s] = {}
1016 for k, v, in self.confdata.items(s):
1017 if _stronly:
1018 res[s][k] = v
1019 continue
1020
1021 try:
1022
1023 res[s][k] = int(v)
1024 except (ValueError, TypeError):
1025 try:
1026
1027 res[s][k] = float(v)
1028 except (ValueError, TypeError):
1029 try:
1030
1031 res[s][k] = _KEYWORDS[v]
1032 except KeyError:
1033 try:
1034 _v = _CONCAT_LIST.split(v)
1035 if len(_v) > 1:
1036
1037
1038 try:
1039 container = _CONTAINERS[_v[0]]
1040 _v.pop(0)
1041 except KeyError:
1042 container = _C_LIST
1043
1044 if container == _C_DICT:
1045 res[s][k] = {}
1046 else:
1047 res[s][k] = []
1048
1049 if container == _C_DICT:
1050
1051
1052 for _vi in _v:
1053 _dk,_dv = re.split(r'[=:]', _vi, 1)
1054 _dk = str(_CLEAR_KEY.sub(r'\1', _dk))
1055 try:
1056 res[s][k][_dk] = int(_dv)
1057 except (ValueError, TypeError):
1058 try:
1059 res[s][k][_dk] = float(_dv)
1060 except (ValueError, TypeError):
1061 res[s][k][_dk] = _dv
1062
1063 elif container == _C_BYTEARRAY:
1064
1065
1066 res[s][k] = bytearray()
1067 for _vi in _v:
1068 try:
1069 res[s][k].append(int(_vi))
1070 except ValueError:
1071
1072 raise YapyDataTreeError(
1073 "Bytearray(0..256) failed: [%s] = %s" %(
1074 str(k),
1075 str(_vi),
1076 )
1077 )
1078
1079 else:
1080
1081 res[s][k] = []
1082 for _vi in _v:
1083 try:
1084 res[s][k].append(int(_vi))
1085 except (ValueError, TypeError):
1086 try:
1087 res[s][k].append(float(_vi))
1088 except (ValueError, TypeError):
1089 res[s][k].append(_vi)
1090
1091
1092 if container == _C_TUPLE:
1093 res[s][k] = tuple(res[s][k])
1094 elif container == _C_SET:
1095 res[s][k] = set(res[s][k])
1096
1097 else:
1098 res[s][k] = v
1099
1100 except TypeError:
1101 if v == None:
1102 res[s][k] = None
1103 else:
1104 raise
1105
1106 return res
1107
1108 - def set(self, section, option, value):
1109 return self.confdata.set(section, option, value)
1110