modelflowib 2.73__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.
- modelBLfunk.py +180 -0
- model_Excel.py +332 -0
- model_cvx.py +139 -0
- model_dynare.py +173 -0
- model_financial_stability.py +88 -0
- model_latex.py +497 -0
- model_latex_class.py +808 -0
- model_parquet_mixin.py +424 -0
- modelclass.py +9828 -0
- modelconstruct.py +1496 -0
- modelconstruct_estimation.py +2872 -0
- modeldash.py +265 -0
- modeldashboot.py +202 -0
- modeldashsidebar.py +456 -0
- modeldekom.py +651 -0
- modeldiff.py +561 -0
- modeldisplay.py +550 -0
- modelestimation.py +1776 -0
- modelestimator_new.py +2613 -0
- modelflowib-2.73.dist-info/METADATA +156 -0
- modelflowib-2.73.dist-info/RECORD +44 -0
- modelflowib-2.73.dist-info/WHEEL +5 -0
- modelflowib-2.73.dist-info/licenses/license.md +10 -0
- modelflowib-2.73.dist-info/top_level.txt +39 -0
- modelgrab.py +318 -0
- modelgrabgdx.py +584 -0
- modelgrabwf2.py +1107 -0
- modelhelp.py +543 -0
- modelhtml.py +606 -0
- modelinvert.py +250 -0
- modeljupyter.py +824 -0
- modeljupytermagic.py +813 -0
- modelmacrograb.py +98 -0
- modelmanipulation.py +1461 -0
- modelmf.py +349 -0
- modelnet.py +114 -0
- modelnewton.py +2178 -0
- modelnormalize.py +430 -0
- modelpattern.py +428 -0
- modelreport.py +2187 -0
- modeluserfunk.py +97 -0
- modelvis.py +1038 -0
- modelwidget.py +718 -0
- modelwidget_input.py +1933 -0
modelpattern.py
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Mon Sep 02 19:32:22 2013
|
|
4
|
+
|
|
5
|
+
This module defines a number of pattern used in PYFS.
|
|
6
|
+
If a new function is intruduced in the model definition language it should added to the
|
|
7
|
+
function names in funkname
|
|
8
|
+
|
|
9
|
+
All functions in the module modeluserfunk will be added to the language and incorporated in the Business
|
|
10
|
+
Logic language
|
|
11
|
+
|
|
12
|
+
@author: Ib
|
|
13
|
+
"""
|
|
14
|
+
import re
|
|
15
|
+
import inspect
|
|
16
|
+
from collections import namedtuple
|
|
17
|
+
from collections import defaultdict
|
|
18
|
+
from typing import NamedTuple, Optional
|
|
19
|
+
|
|
20
|
+
import modelmanipulation as mp
|
|
21
|
+
import modelBLfunk
|
|
22
|
+
|
|
23
|
+
class FrmlParts(NamedTuple):
|
|
24
|
+
"""Parsed components of a FRML statement."""
|
|
25
|
+
whole: str # The full matched FRML line (up to and incl. $)
|
|
26
|
+
frml: str # Literal 'FRML' (case-insensitive)
|
|
27
|
+
frmlname: str # The FRML name (must include <...>)
|
|
28
|
+
expression: str # The RHS expression text including trailing '$'
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# names and lags
|
|
33
|
+
namepat_ng = r'(?:[A-Za-z_{][A-Za-z_{}0-9]*)' # a name non grouped
|
|
34
|
+
namepat = r'(' + namepat_ng + ')' # a name grouped
|
|
35
|
+
lagpat = r'(?:\(([+-][0-9]+)\))?'
|
|
36
|
+
|
|
37
|
+
# comments
|
|
38
|
+
commentchar = '£'
|
|
39
|
+
commentpat = r'('+commentchar+r'.*)'
|
|
40
|
+
|
|
41
|
+
try: # import the names of functions defined in modeluserfunk
|
|
42
|
+
import modeluserfunk
|
|
43
|
+
userfunk = [o.upper() for o,t in inspect.getmembers(modeluserfunk) if not o.startswith('__')]
|
|
44
|
+
except:
|
|
45
|
+
userfunk = []
|
|
46
|
+
|
|
47
|
+
BLfunk = [o.upper() for o,t in inspect.getmembers(modelBLfunk) if not o.startswith('__') ]
|
|
48
|
+
classfunk = modelBLfunk.classfunk
|
|
49
|
+
# Operators
|
|
50
|
+
funkname = 'DLOG SUM_EXCEL DIFF MIN MAX FLOAT NORM.CDF NORM.PPF ABS MOVAVG PCT_GROWTH'.split() + BLfunk+ userfunk + classfunk
|
|
51
|
+
funkname2 = [i+r'(?=\()' for i in funkname] # a function is followed by a (
|
|
52
|
+
opname = r'\*\* != >= <= == [=+-/*@|()$><,.\]\[]'.split() # list of ordinary operators
|
|
53
|
+
oppat = '('+'|'.join(['(?:' + i + ')' for i in funkname2+opname])+')'
|
|
54
|
+
|
|
55
|
+
# Numbers
|
|
56
|
+
numpat = r'((?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]\d+)?)'
|
|
57
|
+
numpat = r'((?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?)'
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Formulars
|
|
61
|
+
dollarpat = r'([$]'
|
|
62
|
+
upat = r'([^$]*\$)' # resten frem til $
|
|
63
|
+
frmlpat = r'(FRML [^$]*\$)' # A FORMULAR for splitting a model in formulars
|
|
64
|
+
optionpat = r'(?:[<][^>]*[>])?' # 0 eller en optioner omsluttet af <>
|
|
65
|
+
optionpat_req = r'(?:[<][^>]*[>])' # required <...> block
|
|
66
|
+
|
|
67
|
+
#White space
|
|
68
|
+
ws = r'[\s]+' # 0 or more white spaces
|
|
69
|
+
ws2 = r'[\s]*' # 1 or more white spaces
|
|
70
|
+
|
|
71
|
+
splitpat = namepat + ws + \
|
|
72
|
+
'(' + namepat_ng + '?' + ws2 + optionpat + ')' + ws + upat # Splits a formular
|
|
73
|
+
splitpat_reqopts = re.compile(
|
|
74
|
+
f"{namepat}{ws}" # 1) FRML (name token)
|
|
75
|
+
f"({optionpat_req})" # 2) frmlname MUST include <...>
|
|
76
|
+
f"{ws}{upat}" # 3) everything up to next $
|
|
77
|
+
, flags=re.IGNORECASE)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# for splitting a model in commands and values
|
|
84
|
+
statementpat = commentpat + '|' + namepat + ws2 + upat
|
|
85
|
+
|
|
86
|
+
#udtrykpat = commentpat + '|' + numpat + '|' + oppat + '|' + namepat + lagpat
|
|
87
|
+
udtrykpat = numpat + '|' + oppat + '|' + namepat + lagpat
|
|
88
|
+
|
|
89
|
+
udtrykre_old = re.compile(udtrykpat)
|
|
90
|
+
nterm = namedtuple('nterm', ['number', 'op', 'var', 'lag'])
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def udtrykre(funks=[]):
|
|
94
|
+
global funkname
|
|
95
|
+
newfunks = [f.__name__.upper() for f in funks]
|
|
96
|
+
funkname = 'DLOG SUM_EXCEL DIFF MIN MAX FLOAT NORM.CDF NORM.PPF ABS MOVAVG PCT_GROWTH'.split() + BLfunk+ userfunk + classfunk + newfunks
|
|
97
|
+
# print(funkname)
|
|
98
|
+
funkname2 = [i+r'(?=\()' for i in funkname] # a function is followed by a (
|
|
99
|
+
opname = r'\*\* != >= <= == [=+-/*@|()$><,.\]\[]'.split() # list of ordinary operators
|
|
100
|
+
oppat = '('+'|'.join(['(?:' + i + ')' for i in funkname2+opname])+')'
|
|
101
|
+
# udtrykpat = commentpat + '|' + numpat + '|' + oppat + '|' + namepat + lagpat
|
|
102
|
+
udtrykpat = numpat + '|' + oppat + '|' + namepat + lagpat
|
|
103
|
+
return re.compile(udtrykpat)
|
|
104
|
+
|
|
105
|
+
#udtrykpatnew([f1,f2])
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def find_frml(equations):
|
|
109
|
+
''' Takes at modeltext and returns a list with where each element is
|
|
110
|
+
a string starting with FRML and ending with $
|
|
111
|
+
It do not check if it is a valid FRML statement '''
|
|
112
|
+
return re.findall(frmlpat, equations, flags=re.IGNORECASE)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def split_frml(frml):
|
|
116
|
+
''' Splits a string with a frml into a tuple with 4 parts:
|
|
117
|
+
|
|
118
|
+
0. The unsplit frml statement
|
|
119
|
+
1. FRML
|
|
120
|
+
2. <Frml name>
|
|
121
|
+
3. <the frml expression>
|
|
122
|
+
|
|
123
|
+
'''
|
|
124
|
+
m = re.search(splitpat, frml)
|
|
125
|
+
if m:
|
|
126
|
+
return m.group(0), m.group(1), m.group(2), m.group(3)
|
|
127
|
+
else:
|
|
128
|
+
return frml
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def split_frml_reqopts(frml: str) -> Optional[FrmlParts]:
|
|
132
|
+
"""
|
|
133
|
+
Splits a FRML string where the FRML name MUST include <...> options.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
FrmlParts named tuple on match, else None.
|
|
137
|
+
"""
|
|
138
|
+
m = re.search(splitpat_reqopts, frml)
|
|
139
|
+
if not m:
|
|
140
|
+
raise ValueError(
|
|
141
|
+
f" FRML does not match required pattern "
|
|
142
|
+
f"'FRML <...> ...$' → got: {frml!r}"
|
|
143
|
+
)
|
|
144
|
+
expr = m.group(3)
|
|
145
|
+
if expr.strip().endswith("$"):
|
|
146
|
+
expr = expr[:-1].strip()
|
|
147
|
+
|
|
148
|
+
return FrmlParts(
|
|
149
|
+
whole=m.group(0),
|
|
150
|
+
frml=m.group(1),
|
|
151
|
+
frmlname=m.group(2),
|
|
152
|
+
expression=expr
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
def find_statements(a_model):
|
|
156
|
+
''' splits a modeltest into comments and statements
|
|
157
|
+
|
|
158
|
+
* a *comment* starts with ! and ends at lineend
|
|
159
|
+
* a *statement* starts with a name and ends with a $ all characters between are considerd part of the statement
|
|
160
|
+
|
|
161
|
+
The statement is not chekked for meaningfulness
|
|
162
|
+
returns a list of tuppels (comment,command,<rest of statement>)
|
|
163
|
+
'''
|
|
164
|
+
return(re.findall(statementpat, a_model))
|
|
165
|
+
|
|
166
|
+
def model_parse_old(equations,funks=[]):
|
|
167
|
+
'''Takes a model returns a list of tupels. Each tupel contains:
|
|
168
|
+
:the compleete formular:
|
|
169
|
+
:FRML:
|
|
170
|
+
:formular name:
|
|
171
|
+
:the expression:
|
|
172
|
+
:list of terms from the expression:
|
|
173
|
+
|
|
174
|
+
The purpose of this function is to make model analysis faster. this is 20 times faster than looping over espressions in a model
|
|
175
|
+
'''
|
|
176
|
+
fatoms = namedtuple('fatoms', 'whole, frml ,frmlname, expression')
|
|
177
|
+
# nterm = namedtuple('nterm', [ 'number', 'op', 'var', 'lag'])
|
|
178
|
+
expressionre= udtrykre(funks)
|
|
179
|
+
ibh = [(fatoms(*c),[nterm(*t) for t in expressionre.findall(c[3])]) for c in (split_frml(f) for f in find_frml(equations.upper()) )]
|
|
180
|
+
return ibh
|
|
181
|
+
|
|
182
|
+
def model_parse(equations,funks=[]):
|
|
183
|
+
'''Takes a model returns a list of tupels. Each tupel contains:
|
|
184
|
+
:the compleete formular:
|
|
185
|
+
:FRML:
|
|
186
|
+
:formular name:
|
|
187
|
+
:the expression:
|
|
188
|
+
:list of terms from the expression:
|
|
189
|
+
|
|
190
|
+
The purpose of this function is to make model analysis faster. this is 20 times faster than looping over espressions in a model
|
|
191
|
+
|
|
192
|
+
This new model_parse handels lags of -0 or +0 which ocours in some models from world bank.
|
|
193
|
+
'''
|
|
194
|
+
fatoms = namedtuple('fatoms', 'whole, frml ,frmlname, expression')
|
|
195
|
+
# nterm = namedtuple('nterm', [ 'number', 'op', 'var', 'lag'])
|
|
196
|
+
expressionre= udtrykre(funks)
|
|
197
|
+
ibh = [(fatoms(*c),
|
|
198
|
+
[ nterm(t[0],t[1],t[2], '' if t[3] == '-0' or t[3]=='+0' else t[3]) for t in expressionre.findall(c[3])])
|
|
199
|
+
for c in (split_frml(f) for f in find_frml(equations.upper()) )]
|
|
200
|
+
return ibh
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def list_extract(equations, silent=True, add_auto_sublists=True):
|
|
204
|
+
''' creates lists used in a model
|
|
205
|
+
|
|
206
|
+
returns a dictonary with the lists
|
|
207
|
+
if a list is defined several times, the first definition is used'''
|
|
208
|
+
liste_dict = {}
|
|
209
|
+
|
|
210
|
+
for comment, command, value in find_statements(equations):
|
|
211
|
+
if command.upper() == 'LIST':
|
|
212
|
+
stripvalue = ' '.join(value.upper().splitlines())
|
|
213
|
+
list_name, list_value = stripvalue[:-1].split('=', 1)
|
|
214
|
+
list_name = list_name.strip()
|
|
215
|
+
|
|
216
|
+
if list_name in liste_dict:
|
|
217
|
+
if not silent:
|
|
218
|
+
print('Warning ', list_name, 'Defined 2 times')
|
|
219
|
+
print('Use ', list_name, liste_dict[list_name])
|
|
220
|
+
continue
|
|
221
|
+
|
|
222
|
+
this_dict = {}
|
|
223
|
+
|
|
224
|
+
for i in list_value.split('/'):
|
|
225
|
+
name, items = [part.strip() for part in i.split(':', 1)]
|
|
226
|
+
|
|
227
|
+
if '*' in items:
|
|
228
|
+
start, end = [x.strip() for x in items.split('*', 1)]
|
|
229
|
+
startitems = re.split(r'(^[A-Z0-9_]*[A-Z_])([0-9]+$)', start)
|
|
230
|
+
enditems = re.split(r'(^[A-Z0-9_]*[A-Z_])([0-9]+$)', end)
|
|
231
|
+
|
|
232
|
+
if len(startitems) != len(enditems):
|
|
233
|
+
raise Exception(f'Range of lists wrong {startitems=} {enditems=}')
|
|
234
|
+
|
|
235
|
+
if len(startitems) == 4:
|
|
236
|
+
if startitems[1] != enditems[1]:
|
|
237
|
+
raise Exception(f'Range prefix mismatch {start=} {end=}')
|
|
238
|
+
label = startitems[1]
|
|
239
|
+
startint = int(startitems[2])
|
|
240
|
+
endint = int(enditems[2])
|
|
241
|
+
elif len(startitems) == 1:
|
|
242
|
+
label = ''
|
|
243
|
+
startint = int(startitems[0])
|
|
244
|
+
endint = int(enditems[0])
|
|
245
|
+
else:
|
|
246
|
+
raise Exception(f'wrong range in list: {startitems=} {enditems=}')
|
|
247
|
+
|
|
248
|
+
itemlist = [label + str(i) for i in range(startint, endint)]
|
|
249
|
+
else:
|
|
250
|
+
itemlist = [t for t in re.split(r'[\s,]+', items) if t]
|
|
251
|
+
|
|
252
|
+
this_dict[name] = itemlist
|
|
253
|
+
|
|
254
|
+
if not this_dict:
|
|
255
|
+
raise Exception(f'Empty list definition for {list_name}')
|
|
256
|
+
|
|
257
|
+
first_sublist_name = list(this_dict.keys())[0]
|
|
258
|
+
first_sublist = this_dict[first_sublist_name]
|
|
259
|
+
list_len = len(first_sublist)
|
|
260
|
+
|
|
261
|
+
for sublist, values in this_dict.items():
|
|
262
|
+
if len(values) != list_len:
|
|
263
|
+
raise Exception(
|
|
264
|
+
f'In {list_name} the length of sublist {sublist} is {len(values)} should be {list_len}'
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
if add_auto_sublists:
|
|
268
|
+
# Only inject auto-sublists that don't collide with explicitly
|
|
269
|
+
# user-defined sublist names. A user list like
|
|
270
|
+
# LIST AGES = AGES : AGE_0 * AGE_5 / AGES_END : 1 0 0 0 0 0
|
|
271
|
+
# already has its own AGES_END sublist; silently overwriting it
|
|
272
|
+
# would be a footgun. We warn (when not silent) and keep the
|
|
273
|
+
# user's value.
|
|
274
|
+
auto_sublists = [
|
|
275
|
+
(first_sublist_name + '_END', ['0'] * (list_len - 1) + ['1']),
|
|
276
|
+
(first_sublist_name + '_NOEND', ['1'] * (list_len - 1) + ['0']),
|
|
277
|
+
(first_sublist_name + '_START', ['1'] + ['0'] * (list_len - 1)),
|
|
278
|
+
(first_sublist_name + '_NOSTART', ['0'] + ['1'] * (list_len - 1)),
|
|
279
|
+
]
|
|
280
|
+
if list_len >= 3:
|
|
281
|
+
auto_sublists.append(
|
|
282
|
+
(first_sublist_name + '_MIDDLE', ['0'] + ['1'] * (list_len - 2) + ['0'])
|
|
283
|
+
)
|
|
284
|
+
auto_sublists.extend([
|
|
285
|
+
(first_sublist_name + '_BEFORE', ['0'] + first_sublist[:-1]),
|
|
286
|
+
(first_sublist_name + '_AFTER', first_sublist[1:] + ['0']),
|
|
287
|
+
])
|
|
288
|
+
|
|
289
|
+
for sub_name, sub_values in auto_sublists:
|
|
290
|
+
if sub_name in this_dict:
|
|
291
|
+
if not silent:
|
|
292
|
+
print(
|
|
293
|
+
f'Warning: auto-sublist {sub_name!r} in list '
|
|
294
|
+
f'{list_name!r} would overwrite a user-defined '
|
|
295
|
+
f'sublist; keeping user value.'
|
|
296
|
+
)
|
|
297
|
+
continue
|
|
298
|
+
this_dict[sub_name] = sub_values
|
|
299
|
+
|
|
300
|
+
liste_dict[list_name] = this_dict
|
|
301
|
+
|
|
302
|
+
return liste_dict
|
|
303
|
+
|
|
304
|
+
def rebuild_list(list_dict):
|
|
305
|
+
"""
|
|
306
|
+
Rebuild one LIST statement from the result of:
|
|
307
|
+
|
|
308
|
+
list_extract(block, add_auto_sublists=False)
|
|
309
|
+
"""
|
|
310
|
+
if len(list_dict) != 1:
|
|
311
|
+
raise Exception(f'Expected exactly one list, got {list(list_dict.keys())}')
|
|
312
|
+
|
|
313
|
+
list_name, sublist_dict = next(iter(list_dict.items()))
|
|
314
|
+
|
|
315
|
+
if not sublist_dict:
|
|
316
|
+
return f'LIST {list_name} = $'
|
|
317
|
+
|
|
318
|
+
subitems = list(sublist_dict.items())
|
|
319
|
+
|
|
320
|
+
namewidth = max(len(subname) for subname, _ in subitems)
|
|
321
|
+
nval = len(subitems[0][1])
|
|
322
|
+
|
|
323
|
+
colwidths = [
|
|
324
|
+
max(len(values[i]) for _, values in subitems)
|
|
325
|
+
for i in range(nval)
|
|
326
|
+
]
|
|
327
|
+
|
|
328
|
+
def format_values(values):
|
|
329
|
+
return ' '.join(
|
|
330
|
+
f'{v:>{w}}' for v, w in zip(values, colwidths)
|
|
331
|
+
).rstrip()
|
|
332
|
+
|
|
333
|
+
parts = [
|
|
334
|
+
f"{subname:<{namewidth}} : {format_values(values)}"
|
|
335
|
+
for subname, values in subitems
|
|
336
|
+
]
|
|
337
|
+
|
|
338
|
+
prefix = f"LIST {list_name} = "
|
|
339
|
+
indent = " " * len(prefix)
|
|
340
|
+
|
|
341
|
+
if len(parts) == 1:
|
|
342
|
+
return prefix + parts[0] + " $"
|
|
343
|
+
|
|
344
|
+
lines = [prefix + parts[0] + " /"]
|
|
345
|
+
for i, part in enumerate(parts[1:], start=1):
|
|
346
|
+
ending = " $" if i == len(parts) - 1 else " /"
|
|
347
|
+
lines.append(indent + part + ending)
|
|
348
|
+
|
|
349
|
+
return "\n".join(lines)
|
|
350
|
+
|
|
351
|
+
# def check_syntax_model(equations,test=True):
|
|
352
|
+
# ''' cheks if equations have syntax errors by calling the python compile.parse '''
|
|
353
|
+
# import ast
|
|
354
|
+
# ok =True
|
|
355
|
+
# try:
|
|
356
|
+
# for frml in find_frml(equations):
|
|
357
|
+
# a, fr, n, udtryk = split_frml(frml)
|
|
358
|
+
# ast.parse(re.sub(r'\n','',re.sub(' ','',udtryk[:-1])))
|
|
359
|
+
# except SyntaxError:
|
|
360
|
+
# print('Syntax error in:',frml)
|
|
361
|
+
# ok =False
|
|
362
|
+
# return ok
|
|
363
|
+
|
|
364
|
+
def get_expressions(equations):
|
|
365
|
+
''' returns a generator of expressions in a model with frml <> expression $ '''
|
|
366
|
+
expressions = (split_frml(f)[3][:-1].replace(r'\n','').replace(r' ','') for f in find_frml(equations))
|
|
367
|
+
return expressions
|
|
368
|
+
|
|
369
|
+
def check_syntax_model(equations):
|
|
370
|
+
mp.check_syntax(get_expressions(equations))
|
|
371
|
+
return True
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def udtryk_parse(udtryk,funks=[]):
|
|
375
|
+
'''returns a list of terms from an expression ie: lhs=rhs $
|
|
376
|
+
or just an expression like x+b '''
|
|
377
|
+
#nterm = namedtuple('nterm', ['comment', 'number', 'op', 'var', 'lag'])
|
|
378
|
+
temp=re.sub(r'\s+', '', udtryk.upper()) # remove all blanks
|
|
379
|
+
xxx = udtrykre(funks=funks).findall(temp) # the compiled re pattern is importet from pattern
|
|
380
|
+
# her laver vi det til en named tuple
|
|
381
|
+
ibh = [nterm(t[0],t[1],t[2], '' if t[3] == '-0' or t[3]=='+0' else t[3]) for t in xxx]
|
|
382
|
+
# ibh = [nterm._make(t) for t in xxx] # Easier to remember by using named tupels .
|
|
383
|
+
return ibh
|
|
384
|
+
|
|
385
|
+
def kw_frml_name(frml_name0, kw,default=None):
|
|
386
|
+
''' find keywords and associated value from string '<kw=xxx,res=kdkdk>' '''
|
|
387
|
+
out = None
|
|
388
|
+
# frml_name=frml_name0.replace(' ','')
|
|
389
|
+
frml_name=frml_name0 # we want to enable values with blanks
|
|
390
|
+
if '<' in frml_name:
|
|
391
|
+
j = frml_name.find('<') # where is the <
|
|
392
|
+
for s in frml_name[j + 1:-1].split(','):
|
|
393
|
+
keyvalue = s.split('=',1)
|
|
394
|
+
if keyvalue[0].upper().strip() == kw.upper():
|
|
395
|
+
if len(keyvalue) == 2:
|
|
396
|
+
out = keyvalue[1].strip()
|
|
397
|
+
else:
|
|
398
|
+
out = True
|
|
399
|
+
if type(out) == type(None) and type(default)!=type(None):
|
|
400
|
+
out=default
|
|
401
|
+
return out
|
|
402
|
+
|
|
403
|
+
def f1():
|
|
404
|
+
return 42
|
|
405
|
+
|
|
406
|
+
def f2():
|
|
407
|
+
return 103
|
|
408
|
+
|
|
409
|
+
if __name__ == '__main__' and 1 :
|
|
410
|
+
#%% nterm = namedtuple('nterm', ['number', 'op', 'var', 'lag'])
|
|
411
|
+
if 0:
|
|
412
|
+
model_parse('frml <> a= b+c( + 0)+3.444 $')
|
|
413
|
+
xx = model_parse('frml <> a+b+b+b=x(-1)+y(-33) $ frml <> a= b+c(-0)+3.444 $')
|
|
414
|
+
for ((frml, fr, n, udtryk), nt) in xx:
|
|
415
|
+
print(f'{udtryk=}')
|
|
416
|
+
for t in nt:
|
|
417
|
+
print(f'{t=} ')
|
|
418
|
+
|
|
419
|
+
print(*udtryk_parse('frml <> a+b+b+b=x(+0)+y(-33) + b+c(-0)/ 1e4 +3.444 $'),sep=' \n')
|
|
420
|
+
|
|
421
|
+
list_extract('list bankdic = bank : Danske , Nordea / danske : yes , no $')
|
|
422
|
+
list_extract('list bankdic = bank : Danske , Nordea $')
|
|
423
|
+
list_extract('list agedic = age : age0 * age101 $')
|
|
424
|
+
list_extract('list yeardic = year : 2023 * 2031 / lag1 : 2022 * 2030 $')
|
|
425
|
+
t = list_extract('LIST AGES = AGES : AGE_0 * AGE_5 / A0T17 : 1 1 1 1 0 $')
|
|
426
|
+
print(rebuild_list(t))
|
|
427
|
+
t2 = list_extract('LIST AGES = AGES : AGE_0 * AGE_5 / A0T17 : 1 1 1 1 0 $',add_auto_sublists=False)
|
|
428
|
+
print(rebuild_list(t2))
|