source: framspy/framsfiles/writer/_parser.py @ 1189

Last change on this file since 1189 was 1104, checked in by Maciej Komosinski, 3 years ago

Added the "framsfiles" module for reading and writing Framsticks-format files (genotypes, settings, scrips, neurons, etc.)

File size: 3.1 KB
Line 
1import warnings
2
3from framsfiles._context import _specs
4from ._serializer import _serialize_value
5
6_EXPECTED_OBJECT_WARNING = 'Encountered item of type {} in list of objects. Skipping.'
7_MISSING_CLASSNAME_WARNING = 'Object defined without classname. Resulting file might be invalid.'
8_INVALID_TYPE_WARINING = 'Field {} in class {} has type {}, {} expected.'
9_LOWER_LIMIT_WARINING = 'Value {} of field {} in class {} is less than {}.'
10_UPPER_LIMIT_WARINING = 'Value {} of field {} in class {} is more than {}.'
11
12_CAST_ERROR = 'Cannot cast {} to {}, aborting.'
13
14
15def _parse_object_list(object_list, context=None):
16    fram_objects = []
17    for obj in object_list:
18        if isinstance(obj, dict):
19            fram_objects.append(_parse_object(obj, context))
20        else:
21            warnings.warn(_EXPECTED_OBJECT_WARNING.format(type(obj)))
22    return '\n'.join(fram_objects)
23
24
25def _parse_object(obj, context=None):
26    line_list = []
27    spec = None
28    classname = obj.get('_classname')
29
30    if classname is None:
31        warnings.warn(_MISSING_CLASSNAME_WARNING)
32    else:
33        line_list = [classname + ':']
34        spec = _specs.get((context, classname))
35
36    for key, value in obj.items():
37        if not _is_classname(key):
38            if spec is not None:
39                _validate_field(key, value, classname, spec)
40            if isinstance(value, str):
41                if _is_multiline(value):
42                    value = _parse_multiline(value)
43                elif _contains_serialized_keyword(value) or _contains_tab(value):
44                    value = _serialize_value(value)
45            elif isinstance(value, (list, dict)):
46                value = _serialize_value(value)
47            line = _to_fram_field_string(key, value)
48            line_list.append(line)
49
50    return '\n'.join(line_list) + '\n'
51
52
53def _validate_field(key, value, classname, spec):
54    _validate_type(key, value, classname, spec)
55    _validate_min(key, value, classname, spec)
56    _validate_max(key, value, classname, spec)
57
58
59def _validate_type(key, value, classname, spec):
60    if not isinstance(value, spec['dtype']):
61        warnings.warn(_INVALID_TYPE_WARINING.format(key, classname, type(value), spec['type']))
62
63
64def _validate_min(key, value, classname, spec):
65    if 'min' in spec:
66        casted = spec['dtype'](value)
67        if casted < spec['min']:
68            warnings.warn(_LOWER_LIMIT_WARINING.format(value, key, classname, spec['min']))
69
70
71def _validate_max(key, value, classname, spec):
72    if 'max' in spec:
73        casted = spec['dtype'](value)
74        if casted > spec['max']:
75            warnings.warn(_UPPER_LIMIT_WARINING.format(value, key, classname, spec['max']))
76
77
78def _is_classname(key):
79    return key == '_classname'
80
81
82def _parse_multiline(value):
83    value = _escape_tildes(value)
84    return _tilde_wrap(value)
85
86
87def _escape_tildes(value):
88    return value.replace('~', '\\~')
89
90
91def _tilde_wrap(value):
92    return '~\n{}~'.format(value)
93
94
95def _to_fram_field_string(key, value):
96    return '{}:{}'.format(key, value)
97
98
99def _contains_serialized_keyword(value):
100    return '@Serialized:' in value
101
102
103def _contains_tab(value):
104    return '\t' in value
105
106
107def _is_multiline(value):
108    return '\n' in value
Note: See TracBrowser for help on using the repository browser.