jsonbp 0.9.2__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.
- jsonbp/__init__.py +31 -0
- jsonbp/array.py +39 -0
- jsonbp/blueprint.py +412 -0
- jsonbp/declaration.py +14 -0
- jsonbp/error.py +117 -0
- jsonbp/error_type.py +17 -0
- jsonbp/exception.py +4 -0
- jsonbp/field.py +15 -0
- jsonbp/field_type.py +5 -0
- jsonbp/parser.py +549 -0
- jsonbp/ply/__init__.py +5 -0
- jsonbp/ply/lex.py +901 -0
- jsonbp/ply/yacc.py +2482 -0
- jsonbp/types.py +42 -0
- jsonbp-0.9.2.dist-info/LICENSE.txt +21 -0
- jsonbp-0.9.2.dist-info/METADATA +205 -0
- jsonbp-0.9.2.dist-info/RECORD +19 -0
- jsonbp-0.9.2.dist-info/WHEEL +5 -0
- jsonbp-0.9.2.dist-info/top_level.txt +1 -0
jsonbp/parser.py
ADDED
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
|
|
2
|
+
from decimal import Decimal
|
|
3
|
+
from .ply import lex as plyLex
|
|
4
|
+
from .ply import yacc as plyYacc
|
|
5
|
+
|
|
6
|
+
from . import field_type
|
|
7
|
+
from .types import primitive_types
|
|
8
|
+
from .exception import SchemaViolation
|
|
9
|
+
from .blueprint import JsonBlueprint
|
|
10
|
+
from .declaration import createDeclaration
|
|
11
|
+
from .field import createField
|
|
12
|
+
from .array import makeArray
|
|
13
|
+
|
|
14
|
+
reserved = (
|
|
15
|
+
'root',
|
|
16
|
+
'node',
|
|
17
|
+
'type',
|
|
18
|
+
'enum',
|
|
19
|
+
'optional',
|
|
20
|
+
'extends',
|
|
21
|
+
'include'
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
literals = (
|
|
25
|
+
'{',
|
|
26
|
+
'}',
|
|
27
|
+
'(',
|
|
28
|
+
')',
|
|
29
|
+
'[',
|
|
30
|
+
']',
|
|
31
|
+
',',
|
|
32
|
+
'=',
|
|
33
|
+
':'
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# List of tokens
|
|
37
|
+
|
|
38
|
+
types = (
|
|
39
|
+
'STRING',
|
|
40
|
+
'BOOLEAN',
|
|
41
|
+
'FLOAT_AMOUNT',
|
|
42
|
+
'INTEGER_AMOUNT',
|
|
43
|
+
'IDENTIFIER',
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
tokens = list(types) + [token.upper() for token in reserved]
|
|
47
|
+
|
|
48
|
+
#------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
def t_STRING(t):
|
|
51
|
+
r'"[^"]*"'
|
|
52
|
+
t.value = t.value[1:-1]
|
|
53
|
+
return t
|
|
54
|
+
|
|
55
|
+
def t_BOOLEAN(t):
|
|
56
|
+
r'true|false'
|
|
57
|
+
t.value = (t.value == 'true')
|
|
58
|
+
return t
|
|
59
|
+
|
|
60
|
+
def t_FLOAT_AMOUNT(t):
|
|
61
|
+
r'[-+]?\d+(\.(\d+)?([eE][-+]?\d+)?|[eE][-+]?\d+)'
|
|
62
|
+
t.value = float(t.value)
|
|
63
|
+
return t
|
|
64
|
+
|
|
65
|
+
def t_INTEGER_AMOUNT(t):
|
|
66
|
+
r'[+-]?\d+'
|
|
67
|
+
t.value = int(t.value)
|
|
68
|
+
return t
|
|
69
|
+
|
|
70
|
+
def t_IDENTIFIER(t):
|
|
71
|
+
r'\w+'
|
|
72
|
+
|
|
73
|
+
identifier = t.value
|
|
74
|
+
if identifier in reserved:
|
|
75
|
+
t.type = identifier.upper()
|
|
76
|
+
|
|
77
|
+
return t
|
|
78
|
+
|
|
79
|
+
#----------------------------------------------------------------
|
|
80
|
+
|
|
81
|
+
def t_newline(t):
|
|
82
|
+
r'\n+'
|
|
83
|
+
t.lexer.lineno += len(t.value)
|
|
84
|
+
|
|
85
|
+
def t_comment(t):
|
|
86
|
+
r'[#][^\n]*'
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
t_ignore = ' \t\r'
|
|
90
|
+
|
|
91
|
+
#---------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
def t_error(t):
|
|
94
|
+
sentence = t.value.split()[0]
|
|
95
|
+
msg = f"Syntax error: Unexpected sentence '{sentence}' on line {t.lineno}"
|
|
96
|
+
raise SchemaViolation(msg)
|
|
97
|
+
|
|
98
|
+
def p_error(p):
|
|
99
|
+
if p == None: raise SchemaViolation("Empty blueprint")
|
|
100
|
+
msg = f"Error parsing line {p.lineno}: token '{p.value}' misplaced"
|
|
101
|
+
raise SchemaViolation(msg)
|
|
102
|
+
|
|
103
|
+
#---------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
def typeExists(typeName, excluded=None):
|
|
106
|
+
excluded = excluded or set()
|
|
107
|
+
|
|
108
|
+
found = (
|
|
109
|
+
blueprint.find_element_declaration(typeName, excluded.copy()) or
|
|
110
|
+
blueprint.find_node_declaration(typeName, excluded.copy()) or
|
|
111
|
+
blueprint.find_enum_declaration(typeName, excluded.copy()))
|
|
112
|
+
|
|
113
|
+
return found != None
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
adhoc_counter = 0
|
|
117
|
+
def getNextAdhoc():
|
|
118
|
+
global adhoc_counter
|
|
119
|
+
adhoc_counter += 1
|
|
120
|
+
return adhoc_counter
|
|
121
|
+
|
|
122
|
+
#---------------- general structure -----------------------------
|
|
123
|
+
|
|
124
|
+
def p_schema(p):
|
|
125
|
+
'''
|
|
126
|
+
schema : schema construction
|
|
127
|
+
| construction
|
|
128
|
+
'''
|
|
129
|
+
|
|
130
|
+
def p_construction(p):
|
|
131
|
+
'''
|
|
132
|
+
construction : type
|
|
133
|
+
| enum
|
|
134
|
+
| node
|
|
135
|
+
| root
|
|
136
|
+
| include
|
|
137
|
+
'''
|
|
138
|
+
|
|
139
|
+
#---------------- constructs -----------------------------
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def p_include(p):
|
|
143
|
+
'''
|
|
144
|
+
include : INCLUDE STRING
|
|
145
|
+
'''
|
|
146
|
+
|
|
147
|
+
inclusionFile = p[2]
|
|
148
|
+
inclusionPath = os.path.join(currentPath, inclusionFile)
|
|
149
|
+
pushEnv(); loadedBlueprint = load(inclusionPath); popEnv()
|
|
150
|
+
|
|
151
|
+
if None == loadedBlueprint:
|
|
152
|
+
msg = f'Unable to open file "{inclusionFile}"'
|
|
153
|
+
raise SchemaViolation(msg)
|
|
154
|
+
|
|
155
|
+
for typeName in loadedBlueprint.collectTypes():
|
|
156
|
+
if typeExists(typeName, excluded=loadedBlueprint.collectSources()):
|
|
157
|
+
msg = f"Error including '{inclusionFile}': type '{typeName}' already defined"
|
|
158
|
+
raise SchemaViolation(msg)
|
|
159
|
+
|
|
160
|
+
blueprint.includes.append(loadedBlueprint)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def p_root(p):
|
|
164
|
+
'''
|
|
165
|
+
root : ROOT array_declaration
|
|
166
|
+
| ROOT single_declaration
|
|
167
|
+
|
|
168
|
+
'''
|
|
169
|
+
|
|
170
|
+
if None != blueprint.root:
|
|
171
|
+
msg = 'Only one root can be defined'
|
|
172
|
+
raise SchemaViolation(msg)
|
|
173
|
+
|
|
174
|
+
blueprint.root = p[2]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def p_node(p):
|
|
178
|
+
'''
|
|
179
|
+
node : NODE IDENTIFIER EXTENDS IDENTIFIER node_declaration
|
|
180
|
+
| NODE IDENTIFIER node_declaration
|
|
181
|
+
'''
|
|
182
|
+
|
|
183
|
+
nodeName = p[2]
|
|
184
|
+
if typeExists(nodeName):
|
|
185
|
+
msg = f"Duplicated type '{nodeName}'"
|
|
186
|
+
raise SchemaViolation(msg)
|
|
187
|
+
|
|
188
|
+
if len(p) == 6:
|
|
189
|
+
baseNode = p[4]
|
|
190
|
+
baseFields = blueprint.find_node_declaration(baseNode)
|
|
191
|
+
|
|
192
|
+
if None == baseFields:
|
|
193
|
+
msg = f"Node '{baseNode}' is not defined"
|
|
194
|
+
raise SchemaViolation(msg)
|
|
195
|
+
|
|
196
|
+
nodeFields = p[5]
|
|
197
|
+
for fieldName, fieldDeclaration in nodeFields.items():
|
|
198
|
+
if fieldName in baseFields:
|
|
199
|
+
msg = f"Field '{fieldName}' in node '{nodeName}' is already defined in base node '{baseNode}'"
|
|
200
|
+
raise SchemaViolation(msg)
|
|
201
|
+
|
|
202
|
+
nodeFields.update(baseFields)
|
|
203
|
+
blueprint.nodes[nodeName] = nodeFields
|
|
204
|
+
|
|
205
|
+
else:
|
|
206
|
+
nodeFields = p[3]
|
|
207
|
+
blueprint.nodes[nodeName] = nodeFields
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def p_node_specs(p):
|
|
211
|
+
'''
|
|
212
|
+
node_declaration : '{' attributes '}'
|
|
213
|
+
'''
|
|
214
|
+
|
|
215
|
+
decls = p[2]
|
|
216
|
+
newNode = dict()
|
|
217
|
+
for decl in decls:
|
|
218
|
+
newNode[decl[0]] = decl[1]
|
|
219
|
+
|
|
220
|
+
p[0] = newNode
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def createType(newTypeName, declaration):
|
|
224
|
+
base_type = declaration.typeName
|
|
225
|
+
origin = blueprint.find_element_declaration(
|
|
226
|
+
base_type)
|
|
227
|
+
|
|
228
|
+
newType = dict()
|
|
229
|
+
for specName, value in origin.items():
|
|
230
|
+
newType[specName] = value
|
|
231
|
+
|
|
232
|
+
for spec in declaration.specs:
|
|
233
|
+
specName, value = spec
|
|
234
|
+
if not specName in origin:
|
|
235
|
+
msg = f"Type '{newTypeName}' ({declaration.typeName}) has no attribute '{specName}'"
|
|
236
|
+
raise SchemaViolation(msg)
|
|
237
|
+
|
|
238
|
+
oldValue = newType[specName]
|
|
239
|
+
if type(oldValue) == Decimal and type(value) == float: value = Decimal(value)
|
|
240
|
+
if type(oldValue) == float and type(value) == int: value = float(value)
|
|
241
|
+
|
|
242
|
+
if type(value) != type(oldValue):
|
|
243
|
+
msg = f"New value for specificity '{specName}' is {type(value).__name__}, but it expects {type(oldValue).__name__}"
|
|
244
|
+
raise SchemaViolation(msg)
|
|
245
|
+
|
|
246
|
+
newType[specName] = value
|
|
247
|
+
|
|
248
|
+
while not base_type in primitive_types:
|
|
249
|
+
parent_type = blueprint.derived_types[base_type]
|
|
250
|
+
base_type = parent_type['__baseType__']
|
|
251
|
+
|
|
252
|
+
newType['__baseType__'] = base_type
|
|
253
|
+
blueprint.derived_types[newTypeName] = newType
|
|
254
|
+
return newType
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def p_type(p):
|
|
258
|
+
'''
|
|
259
|
+
type : TYPE IDENTIFIER ':' element_declaration
|
|
260
|
+
'''
|
|
261
|
+
|
|
262
|
+
typeName = p[2]
|
|
263
|
+
if typeExists(typeName):
|
|
264
|
+
msg = f"Duplicated type '{typeName}'"
|
|
265
|
+
raise SchemaViolation(msg)
|
|
266
|
+
|
|
267
|
+
declaration = p[4]
|
|
268
|
+
createType(typeName, declaration)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
#---------------- attributes ----------------------------
|
|
272
|
+
|
|
273
|
+
def p_attributes(p):
|
|
274
|
+
'''
|
|
275
|
+
attributes : attributes ',' attribute
|
|
276
|
+
| attribute
|
|
277
|
+
'''
|
|
278
|
+
|
|
279
|
+
if len(p) == 4: p[1].append(p[3])
|
|
280
|
+
if len(p) == 2: p[1] = [p[1]]
|
|
281
|
+
p[0] = p[1]
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def p_attribute(p):
|
|
285
|
+
'''
|
|
286
|
+
attribute : OPTIONAL attribution
|
|
287
|
+
| attribution
|
|
288
|
+
'''
|
|
289
|
+
|
|
290
|
+
if len(p) == 3:
|
|
291
|
+
fieldName, fieldData = p[2]
|
|
292
|
+
fieldData.setOptional()
|
|
293
|
+
p[0] = p[2]
|
|
294
|
+
|
|
295
|
+
else:
|
|
296
|
+
p[0] = p[1]
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def p_attribution(p):
|
|
300
|
+
'''
|
|
301
|
+
attribution : IDENTIFIER ':' array_declaration
|
|
302
|
+
| IDENTIFIER ':' single_declaration
|
|
303
|
+
'''
|
|
304
|
+
|
|
305
|
+
p[0] = (p[1], p[3])
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def p_array_declaration(p):
|
|
309
|
+
'''
|
|
310
|
+
array_declaration : single_declaration '[' specificities ']'
|
|
311
|
+
| single_declaration '[' ']'
|
|
312
|
+
'''
|
|
313
|
+
|
|
314
|
+
jArray = makeArray(p[1])
|
|
315
|
+
|
|
316
|
+
if len(p) == 5:
|
|
317
|
+
for specificity in p[3]:
|
|
318
|
+
spec, value = specificity
|
|
319
|
+
jArray.applySpec(spec, value)
|
|
320
|
+
|
|
321
|
+
p[0] = jArray
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def p_single_declaration(p):
|
|
325
|
+
'''
|
|
326
|
+
single_declaration : node_declaration
|
|
327
|
+
| enum_declaration
|
|
328
|
+
| element_declaration
|
|
329
|
+
'''
|
|
330
|
+
|
|
331
|
+
declaration = p[1]
|
|
332
|
+
if isinstance(declaration, dict):
|
|
333
|
+
adhoc_node = '_node_type_' + str(getNextAdhoc()) + '_'
|
|
334
|
+
blueprint.nodes[adhoc_node] = declaration
|
|
335
|
+
fieldKind = field_type.NODE
|
|
336
|
+
fieldId = adhoc_node
|
|
337
|
+
|
|
338
|
+
elif isinstance(declaration, list):
|
|
339
|
+
adhoc_enum = '_enum_type_' + str(getNextAdhoc()) + '_'
|
|
340
|
+
blueprint.enums[adhoc_enum] = declaration
|
|
341
|
+
fieldKind = field_type.ENUM
|
|
342
|
+
fieldId = adhoc_enum
|
|
343
|
+
|
|
344
|
+
else:
|
|
345
|
+
declType = declaration.typeName
|
|
346
|
+
if blueprint.find_element_declaration(declType):
|
|
347
|
+
fieldKind = field_type.SIMPLE
|
|
348
|
+
|
|
349
|
+
if not declaration.isCustomized():
|
|
350
|
+
fieldId = declaration.typeName
|
|
351
|
+
|
|
352
|
+
else:
|
|
353
|
+
adhoc_type = '_simple_type_' + str(getNextAdhoc()) + '_'
|
|
354
|
+
createType(adhoc_type, declaration)
|
|
355
|
+
fieldId = adhoc_type
|
|
356
|
+
|
|
357
|
+
elif blueprint.find_enum_declaration(declType):
|
|
358
|
+
fieldKind = field_type.ENUM
|
|
359
|
+
fieldId = declType
|
|
360
|
+
|
|
361
|
+
elif blueprint.find_node_declaration(declType):
|
|
362
|
+
fieldKind = field_type.NODE
|
|
363
|
+
fieldId = declType
|
|
364
|
+
|
|
365
|
+
p[0] = createField(fieldKind, fieldId)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def p_element_declaration(p):
|
|
369
|
+
'''
|
|
370
|
+
element_declaration : IDENTIFIER '(' specificities ')'
|
|
371
|
+
| IDENTIFIER
|
|
372
|
+
'''
|
|
373
|
+
|
|
374
|
+
typeName = p[1]
|
|
375
|
+
|
|
376
|
+
if len(p) == 5:
|
|
377
|
+
not_simple = (
|
|
378
|
+
blueprint.find_node_declaration(typeName) or
|
|
379
|
+
blueprint.find_enum_declaration(typeName))
|
|
380
|
+
|
|
381
|
+
if not_simple:
|
|
382
|
+
msg = f"Unable to apply specificities to '{typeName}', only simple types can be specialized"
|
|
383
|
+
raise SchemaViolation(msg)
|
|
384
|
+
|
|
385
|
+
if not blueprint.find_element_declaration(typeName):
|
|
386
|
+
msg = f"Unknown simple type '{typeName}'"
|
|
387
|
+
raise SchemaViolation(msg)
|
|
388
|
+
|
|
389
|
+
specs = p[3]
|
|
390
|
+
|
|
391
|
+
else:
|
|
392
|
+
if not typeExists(typeName):
|
|
393
|
+
msg = f"Type not declared: '{typeName}'"
|
|
394
|
+
raise SchemaViolation(msg)
|
|
395
|
+
|
|
396
|
+
specs = list()
|
|
397
|
+
|
|
398
|
+
p[0] = createDeclaration(typeName, specs)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def p_specificities(p):
|
|
402
|
+
'''
|
|
403
|
+
specificities : specificities ',' specificity
|
|
404
|
+
| specificity
|
|
405
|
+
'''
|
|
406
|
+
|
|
407
|
+
if len(p) == 4: p[1].append(p[3])
|
|
408
|
+
if len(p) == 2: p[1] = [p[1]]
|
|
409
|
+
p[0] = p[1]
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def p_specificity(p):
|
|
413
|
+
'''
|
|
414
|
+
specificity : IDENTIFIER '=' specified_value
|
|
415
|
+
'''
|
|
416
|
+
|
|
417
|
+
p[0] = (p[1], p[3])
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def p_specified_value(p):
|
|
421
|
+
'''
|
|
422
|
+
specified_value : STRING
|
|
423
|
+
| FLOAT_AMOUNT
|
|
424
|
+
| INTEGER_AMOUNT
|
|
425
|
+
| BOOLEAN
|
|
426
|
+
'''
|
|
427
|
+
|
|
428
|
+
p[0] = p[1]
|
|
429
|
+
|
|
430
|
+
#---------------- enums -----------------------------
|
|
431
|
+
|
|
432
|
+
def p_enum(p):
|
|
433
|
+
'''
|
|
434
|
+
enum : ENUM IDENTIFIER enum_declaration
|
|
435
|
+
'''
|
|
436
|
+
|
|
437
|
+
enum_name = p[2]
|
|
438
|
+
if typeExists(enum_name):
|
|
439
|
+
msg = f"Duplicated type '{enum_name}'"
|
|
440
|
+
raise SchemaViolation(msg)
|
|
441
|
+
|
|
442
|
+
blueprint.enums[enum_name] = p[3]
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def p_enum_declaration(p):
|
|
446
|
+
'''
|
|
447
|
+
enum_declaration : '{' constants '}'
|
|
448
|
+
'''
|
|
449
|
+
|
|
450
|
+
p[0] = p[2]
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def p_constants(p):
|
|
454
|
+
'''
|
|
455
|
+
constants : constants ',' IDENTIFIER
|
|
456
|
+
| IDENTIFIER
|
|
457
|
+
'''
|
|
458
|
+
|
|
459
|
+
if len(p) == 4:
|
|
460
|
+
p[1].append(p[3])
|
|
461
|
+
p[0] = p[1]
|
|
462
|
+
|
|
463
|
+
else:
|
|
464
|
+
p[0] = [p[1]]
|
|
465
|
+
|
|
466
|
+
#---------------------------------------------------------------
|
|
467
|
+
|
|
468
|
+
from threading import Lock
|
|
469
|
+
|
|
470
|
+
_mutex = Lock()
|
|
471
|
+
_loadedFiles = dict()
|
|
472
|
+
_pushedEnvs = list()
|
|
473
|
+
|
|
474
|
+
def setupEnv(contentPath, output):
|
|
475
|
+
global blueprint, currentPath
|
|
476
|
+
currentPath = contentPath
|
|
477
|
+
blueprint = output
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def pushEnv():
|
|
481
|
+
env = (currentPath, blueprint)
|
|
482
|
+
_pushedEnvs.append(env)
|
|
483
|
+
_mutex.release()
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
def popEnv():
|
|
487
|
+
global currentPath, blueprint
|
|
488
|
+
|
|
489
|
+
_mutex.acquire()
|
|
490
|
+
env = _pushedEnvs.pop()
|
|
491
|
+
(currentPath, blueprint) = env
|
|
492
|
+
|
|
493
|
+
#---------------------------------------------------------------
|
|
494
|
+
|
|
495
|
+
import os
|
|
496
|
+
|
|
497
|
+
def load(filepath):
|
|
498
|
+
abspath = os.path.abspath(filepath)
|
|
499
|
+
if abspath in _loadedFiles:
|
|
500
|
+
return _loadedFiles[abspath]
|
|
501
|
+
|
|
502
|
+
try:
|
|
503
|
+
with open(filepath, "r") as fd:
|
|
504
|
+
contents = fd.read()
|
|
505
|
+
|
|
506
|
+
except FileNotFoundError:
|
|
507
|
+
return None
|
|
508
|
+
|
|
509
|
+
return loads(contents,
|
|
510
|
+
os.path.dirname(filepath),
|
|
511
|
+
os.path.basename(filepath))
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def loads(contents, contentPath='.', contentName=None):
|
|
515
|
+
lexer = plyLex.lex()
|
|
516
|
+
parser = plyYacc.yacc()
|
|
517
|
+
|
|
518
|
+
try:
|
|
519
|
+
_mutex.acquire()
|
|
520
|
+
result = JsonBlueprint()
|
|
521
|
+
setupEnv(contentPath, result)
|
|
522
|
+
parser.parse(contents)
|
|
523
|
+
|
|
524
|
+
if None == blueprint.root and len(_pushedEnvs) == 0:
|
|
525
|
+
msg = 'No root defined at topmost level'
|
|
526
|
+
raise SchemaViolation(msg)
|
|
527
|
+
|
|
528
|
+
if None != contentName:
|
|
529
|
+
contentFullpath = os.path.join(contentPath, contentName)
|
|
530
|
+
abspath = os.path.abspath(contentFullpath)
|
|
531
|
+
_loadedFiles[abspath] = result
|
|
532
|
+
|
|
533
|
+
return result
|
|
534
|
+
|
|
535
|
+
finally:
|
|
536
|
+
_mutex.release()
|
|
537
|
+
|
|
538
|
+
#------------------------------------------------------------------------------
|
|
539
|
+
|
|
540
|
+
def invalidateCache():
|
|
541
|
+
global _loadedFiles
|
|
542
|
+
|
|
543
|
+
try:
|
|
544
|
+
_mutex.acquire()
|
|
545
|
+
_loadedFiles = dict()
|
|
546
|
+
|
|
547
|
+
finally:
|
|
548
|
+
_mutex.release()
|
|
549
|
+
|