44import sys
55import urlparse
66import re
7+ import logging
8+
79from typing import Any , Union
810from .sourceline import SourceLine , lineno_re , bullets , indent
911
12+ _logger = logging .getLogger ("salad" )
1013
1114class ValidationException (Exception ):
1215 pass
@@ -54,12 +57,14 @@ def vpformat(datum): # type: (Any) -> str
5457 return a
5558
5659
57- def validate_ex (expected_schema , # type: Schema
58- datum , # type: Any
59- identifiers = None , # type: Set[unicode]
60- strict = False , # type: bool
61- foreign_properties = None , # type: Set[unicode]
62- raise_ex = True # type: bool
60+ def validate_ex (expected_schema , # type: Schema
61+ datum , # type: Any
62+ identifiers = None , # type: Set[unicode]
63+ strict = False , # type: bool
64+ foreign_properties = None , # type: Set[unicode]
65+ raise_ex = True , # type: bool
66+ strict_foreign_properties = False , # type: bool
67+ logger = _logger # type: logging.Logger
6368 ):
6469 # type: (...) -> bool
6570 """Determine if a python datum is an instance of a schema."""
@@ -167,9 +172,11 @@ def validate_ex(expected_schema, # type: Schema
167172 for i , d in enumerate (datum ):
168173 try :
169174 sl = SourceLine (datum , i , ValidationException )
170- if not validate_ex (expected_schema .items , d , identifiers , strict = strict ,
175+ if not validate_ex (expected_schema .items , d , identifiers ,
176+ strict = strict ,
171177 foreign_properties = foreign_properties ,
172- raise_ex = raise_ex ):
178+ raise_ex = raise_ex ,
179+ strict_foreign_properties = strict_foreign_properties ):
173180 return False
174181 except ValidationException as v :
175182 if raise_ex :
@@ -186,7 +193,8 @@ def validate_ex(expected_schema, # type: Schema
186193 return False
187194 elif isinstance (expected_schema , avro .schema .UnionSchema ):
188195 for s in expected_schema .schemas :
189- if validate_ex (s , datum , identifiers , strict = strict , raise_ex = False ):
196+ if validate_ex (s , datum , identifiers , strict = strict , raise_ex = False ,
197+ strict_foreign_properties = strict_foreign_properties ):
190198 return True
191199
192200 if not raise_ex :
@@ -207,7 +215,9 @@ def validate_ex(expected_schema, # type: Schema
207215 checked .append (s )
208216 try :
209217 validate_ex (s , datum , identifiers , strict = strict ,
210- foreign_properties = foreign_properties , raise_ex = True )
218+ foreign_properties = foreign_properties ,
219+ raise_ex = True ,
220+ strict_foreign_properties = strict_foreign_properties )
211221 except ClassValidationException as e :
212222 raise
213223 except ValidationException as e :
@@ -256,8 +266,10 @@ def validate_ex(expected_schema, # type: Schema
256266
257267 try :
258268 sl = SourceLine (datum , f .name , unicode )
259- if not validate_ex (f .type , fieldval , identifiers , strict = strict , foreign_properties = foreign_properties ,
260- raise_ex = raise_ex ):
269+ if not validate_ex (f .type , fieldval , identifiers , strict = strict ,
270+ foreign_properties = foreign_properties ,
271+ raise_ex = raise_ex ,
272+ strict_foreign_properties = strict_foreign_properties ):
261273 return False
262274 except ValidationException as v :
263275 if f .name not in datum :
@@ -266,24 +278,34 @@ def validate_ex(expected_schema, # type: Schema
266278 errors .append (sl .makeError (u"the `%s` field is not valid because\n %s" % (
267279 f .name , indent (str (v )))))
268280
269- if strict :
270- for d in datum :
271- found = False
272- for f in expected_schema .fields :
273- if d == f .name :
274- found = True
275- if not found :
276- sl = SourceLine (datum , d , unicode )
277- if d not in identifiers and d not in foreign_properties and d [0 ] not in ("@" , "$" ):
278- if not raise_ex :
279- return False
280- split = urlparse .urlsplit (d )
281- if split .scheme :
282- errors .append (sl .makeError (
283- u"unrecognized extension field `%s` and strict is True. Did you include a $schemas section?" % (d )))
281+ for d in datum :
282+ found = False
283+ for f in expected_schema .fields :
284+ if d == f .name :
285+ found = True
286+ if not found :
287+ sl = SourceLine (datum , d , unicode )
288+ if d not in identifiers and d not in foreign_properties and d [0 ] not in ("@" , "$" ):
289+ if (d not in identifiers and strict ) and (
290+ d not in foreign_properties and strict_foreign_properties ) and not raise_ex :
291+ return False
292+ split = urlparse .urlsplit (d )
293+ if split .scheme :
294+ err = sl .makeError (u"unrecognized extension field `%s`%s."
295+ " Did you include "
296+ "a $schemas section?" % (
297+ d , " and strict_foreign_properties is True" if strict_foreign_properties else "" ))
298+ if strict_foreign_properties :
299+ errors .append (err )
300+ else :
301+ logger .warn (err )
302+ else :
303+ err = sl .makeError (u"invalid field `%s`, expected one of: %s" % (
304+ d , ", " .join ("'%s'" % fn .name for fn in expected_schema .fields )))
305+ if strict :
306+ errors .append (err )
284307 else :
285- errors .append (sl .makeError (u"invalid field `%s`, expected one of: %s" % (
286- d , ", " .join ("'%s'" % fn .name for fn in expected_schema .fields ))))
308+ logger .warn (err )
287309
288310 if errors :
289311 if raise_ex :
0 commit comments