Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/jsonschema/_keywords.py: 16%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

246 statements  

1from fractions import Fraction 

2import re 

3 

4from jsonschema._utils import ( 

5 ensure_list, 

6 equal, 

7 extras_msg, 

8 find_additional_properties, 

9 find_evaluated_item_indexes_by_schema, 

10 find_evaluated_property_keys_by_schema, 

11 uniq, 

12) 

13from jsonschema.exceptions import FormatError, ValidationError 

14 

15 

16def patternProperties(validator, patternProperties, instance, schema): 

17 if not validator.is_type(instance, "object"): 

18 return 

19 

20 for pattern, subschema in patternProperties.items(): 

21 for k, v in instance.items(): 

22 if re.search(pattern, k): 

23 yield from validator.descend( 

24 v, subschema, path=k, schema_path=pattern, 

25 ) 

26 

27 

28def propertyNames(validator, propertyNames, instance, schema): 

29 if not validator.is_type(instance, "object"): 

30 return 

31 

32 for property in instance: 

33 yield from validator.descend(instance=property, schema=propertyNames) 

34 

35 

36def additionalProperties(validator, aP, instance, schema): 

37 if not validator.is_type(instance, "object"): 

38 return 

39 

40 extras = set(find_additional_properties(instance, schema)) 

41 

42 if validator.is_type(aP, "object"): 

43 for extra in extras: 

44 yield from validator.descend(instance[extra], aP, path=extra) 

45 elif not aP and extras: 

46 if "patternProperties" in schema: 

47 verb = "does" if len(extras) == 1 else "do" 

48 joined = ", ".join(repr(each) for each in sorted(extras)) 

49 patterns = ", ".join( 

50 repr(each) for each in sorted(schema["patternProperties"]) 

51 ) 

52 error = f"{joined} {verb} not match any of the regexes: {patterns}" 

53 yield ValidationError(error) 

54 else: 

55 error = "Additional properties are not allowed (%s %s unexpected)" 

56 yield ValidationError(error % extras_msg(sorted(extras, key=str))) 

57 

58 

59def items(validator, items, instance, schema): 

60 if not validator.is_type(instance, "array"): 

61 return 

62 

63 prefix = len(schema.get("prefixItems", [])) 

64 total = len(instance) 

65 extra = total - prefix 

66 if extra <= 0: 

67 return 

68 

69 if items is False: 

70 rest = instance[prefix:] if extra != 1 else instance[prefix] 

71 item = "items" if prefix != 1 else "item" 

72 yield ValidationError( 

73 f"Expected at most {prefix} {item} but found {extra} " 

74 f"extra: {rest!r}", 

75 ) 

76 else: 

77 for index in range(prefix, total): 

78 yield from validator.descend( 

79 instance=instance[index], 

80 schema=items, 

81 path=index, 

82 ) 

83 

84 

85def const(validator, const, instance, schema): 

86 if not equal(instance, const): 

87 yield ValidationError(f"{const!r} was expected") 

88 

89 

90def contains(validator, contains, instance, schema): 

91 if not validator.is_type(instance, "array"): 

92 return 

93 

94 matches = 0 

95 min_contains = schema.get("minContains", 1) 

96 max_contains = schema.get("maxContains", len(instance)) 

97 

98 contains_validator = validator.evolve(schema=contains) 

99 

100 for each in instance: 

101 if contains_validator.is_valid(each): 

102 matches += 1 

103 if matches > max_contains: 

104 yield ValidationError( 

105 "Too many items match the given schema " 

106 f"(expected at most {max_contains})", 

107 validator="maxContains", 

108 validator_value=max_contains, 

109 ) 

110 return 

111 

112 if matches < min_contains: 

113 if not matches: 

114 yield ValidationError( 

115 f"{instance!r} does not contain items " 

116 "matching the given schema", 

117 ) 

118 else: 

119 yield ValidationError( 

120 "Too few items match the given schema (expected at least " 

121 f"{min_contains} but only {matches} matched)", 

122 validator="minContains", 

123 validator_value=min_contains, 

124 ) 

125 

126 

127def exclusiveMinimum(validator, minimum, instance, schema): 

128 if not validator.is_type(instance, "number"): 

129 return 

130 

131 if instance <= minimum: 

132 yield ValidationError( 

133 f"{instance!r} is less than or equal to " 

134 f"the minimum of {minimum!r}", 

135 ) 

136 

137 

138def exclusiveMaximum(validator, maximum, instance, schema): 

139 if not validator.is_type(instance, "number"): 

140 return 

141 

142 if instance >= maximum: 

143 yield ValidationError( 

144 f"{instance!r} is greater than or equal " 

145 f"to the maximum of {maximum!r}", 

146 ) 

147 

148 

149def minimum(validator, minimum, instance, schema): 

150 if not validator.is_type(instance, "number"): 

151 return 

152 

153 if instance < minimum: 

154 message = f"{instance!r} is less than the minimum of {minimum!r}" 

155 yield ValidationError(message) 

156 

157 

158def maximum(validator, maximum, instance, schema): 

159 if not validator.is_type(instance, "number"): 

160 return 

161 

162 if instance > maximum: 

163 message = f"{instance!r} is greater than the maximum of {maximum!r}" 

164 yield ValidationError(message) 

165 

166 

167def multipleOf(validator, dB, instance, schema): 

168 if not validator.is_type(instance, "number"): 

169 return 

170 

171 if isinstance(dB, float): 

172 quotient = instance / dB 

173 try: 

174 failed = int(quotient) != quotient 

175 except OverflowError: 

176 # When `instance` is large and `dB` is less than one, 

177 # quotient can overflow to infinity; and then casting to int 

178 # raises an error. 

179 # 

180 # In this case we fall back to Fraction logic, which is 

181 # exact and cannot overflow. The performance is also 

182 # acceptable: we try the fast all-float option first, and 

183 # we know that fraction(dB) can have at most a few hundred 

184 # digits in each part. The worst-case slowdown is therefore 

185 # for already-slow enormous integers or Decimals. 

186 failed = (Fraction(instance) / Fraction(dB)).denominator != 1 

187 else: 

188 failed = instance % dB 

189 

190 if failed: 

191 yield ValidationError(f"{instance!r} is not a multiple of {dB}") 

192 

193 

194def minItems(validator, mI, instance, schema): 

195 if validator.is_type(instance, "array") and len(instance) < mI: 

196 message = "should be non-empty" if mI == 1 else "is too short" 

197 yield ValidationError(f"{instance!r} {message}") 

198 

199 

200def maxItems(validator, mI, instance, schema): 

201 if validator.is_type(instance, "array") and len(instance) > mI: 

202 message = "is expected to be empty" if mI == 0 else "is too long" 

203 yield ValidationError(f"{instance!r} {message}") 

204 

205 

206def uniqueItems(validator, uI, instance, schema): 

207 if ( 

208 uI 

209 and validator.is_type(instance, "array") 

210 and not uniq(instance) 

211 ): 

212 yield ValidationError(f"{instance!r} has non-unique elements") 

213 

214 

215def pattern(validator, patrn, instance, schema): 

216 if ( 

217 validator.is_type(instance, "string") 

218 and not re.search(patrn, instance) 

219 ): 

220 yield ValidationError(f"{instance!r} does not match {patrn!r}") 

221 

222 

223def format(validator, format, instance, schema): 

224 if validator.format_checker is not None: 

225 try: 

226 validator.format_checker.check(instance, format) 

227 except FormatError as error: 

228 yield ValidationError(error.message, cause=error.cause) 

229 

230 

231def minLength(validator, mL, instance, schema): 

232 if validator.is_type(instance, "string") and len(instance) < mL: 

233 message = "should be non-empty" if mL == 1 else "is too short" 

234 yield ValidationError(f"{instance!r} {message}") 

235 

236 

237def maxLength(validator, mL, instance, schema): 

238 if validator.is_type(instance, "string") and len(instance) > mL: 

239 message = "is expected to be empty" if mL == 0 else "is too long" 

240 yield ValidationError(f"{instance!r} {message}") 

241 

242 

243def dependentRequired(validator, dependentRequired, instance, schema): 

244 if not validator.is_type(instance, "object"): 

245 return 

246 

247 for property, dependency in dependentRequired.items(): 

248 if property not in instance: 

249 continue 

250 

251 for each in dependency: 

252 if each not in instance: 

253 message = f"{each!r} is a dependency of {property!r}" 

254 yield ValidationError(message) 

255 

256 

257def dependentSchemas(validator, dependentSchemas, instance, schema): 

258 if not validator.is_type(instance, "object"): 

259 return 

260 

261 for property, dependency in dependentSchemas.items(): 

262 if property not in instance: 

263 continue 

264 yield from validator.descend( 

265 instance, dependency, schema_path=property, 

266 ) 

267 

268 

269def enum(validator, enums, instance, schema): 

270 if all(not equal(each, instance) for each in enums): 

271 yield ValidationError(f"{instance!r} is not one of {enums!r}") 

272 

273 

274def ref(validator, ref, instance, schema): 

275 yield from validator._validate_reference(ref=ref, instance=instance) 

276 

277 

278def dynamicRef(validator, dynamicRef, instance, schema): 

279 yield from validator._validate_reference(ref=dynamicRef, instance=instance) 

280 

281 

282def type(validator, types, instance, schema): 

283 types = ensure_list(types) 

284 

285 if not any(validator.is_type(instance, type) for type in types): 

286 reprs = ", ".join(repr(type) for type in types) 

287 yield ValidationError(f"{instance!r} is not of type {reprs}") 

288 

289 

290def properties(validator, properties, instance, schema): 

291 if not validator.is_type(instance, "object"): 

292 return 

293 

294 for property, subschema in properties.items(): 

295 if property in instance: 

296 yield from validator.descend( 

297 instance[property], 

298 subschema, 

299 path=property, 

300 schema_path=property, 

301 ) 

302 

303 

304def required(validator, required, instance, schema): 

305 if not validator.is_type(instance, "object"): 

306 return 

307 for property in required: 

308 if property not in instance: 

309 yield ValidationError(f"{property!r} is a required property") 

310 

311 

312def minProperties(validator, mP, instance, schema): 

313 if validator.is_type(instance, "object") and len(instance) < mP: 

314 message = ( 

315 "should be non-empty" if mP == 1 

316 else "does not have enough properties" 

317 ) 

318 yield ValidationError(f"{instance!r} {message}") 

319 

320 

321def maxProperties(validator, mP, instance, schema): 

322 if not validator.is_type(instance, "object"): 

323 return 

324 if validator.is_type(instance, "object") and len(instance) > mP: 

325 message = ( 

326 "is expected to be empty" if mP == 0 

327 else "has too many properties" 

328 ) 

329 yield ValidationError(f"{instance!r} {message}") 

330 

331 

332def allOf(validator, allOf, instance, schema): 

333 for index, subschema in enumerate(allOf): 

334 yield from validator.descend(instance, subschema, schema_path=index) 

335 

336 

337def anyOf(validator, anyOf, instance, schema): 

338 all_errors = [] 

339 for index, subschema in enumerate(anyOf): 

340 errs = list(validator.descend(instance, subschema, schema_path=index)) 

341 if not errs: 

342 break 

343 all_errors.extend(errs) 

344 else: 

345 yield ValidationError( 

346 f"{instance!r} is not valid under any of the given schemas", 

347 context=all_errors, 

348 ) 

349 

350 

351def oneOf(validator, oneOf, instance, schema): 

352 subschemas = enumerate(oneOf) 

353 all_errors = [] 

354 for index, subschema in subschemas: 

355 errs = list(validator.descend(instance, subschema, schema_path=index)) 

356 if not errs: 

357 first_valid = subschema 

358 break 

359 all_errors.extend(errs) 

360 else: 

361 yield ValidationError( 

362 f"{instance!r} is not valid under any of the given schemas", 

363 context=all_errors, 

364 ) 

365 

366 more_valid = [ 

367 each for _, each in subschemas 

368 if validator.evolve(schema=each).is_valid(instance) 

369 ] 

370 if more_valid: 

371 more_valid.append(first_valid) 

372 reprs = ", ".join(repr(schema) for schema in more_valid) 

373 yield ValidationError(f"{instance!r} is valid under each of {reprs}") 

374 

375 

376def not_(validator, not_schema, instance, schema): 

377 if validator.evolve(schema=not_schema).is_valid(instance): 

378 message = f"{instance!r} should not be valid under {not_schema!r}" 

379 yield ValidationError(message) 

380 

381 

382def if_(validator, if_schema, instance, schema): 

383 if validator.evolve(schema=if_schema).is_valid(instance): 

384 if "then" in schema: 

385 then = schema["then"] 

386 yield from validator.descend(instance, then, schema_path="then") 

387 elif "else" in schema: 

388 else_ = schema["else"] 

389 yield from validator.descend(instance, else_, schema_path="else") 

390 

391 

392def unevaluatedItems(validator, unevaluatedItems, instance, schema): 

393 if not validator.is_type(instance, "array"): 

394 return 

395 evaluated_item_indexes = find_evaluated_item_indexes_by_schema( 

396 validator, instance, schema, 

397 ) 

398 unevaluated_items = [ 

399 item for index, item in enumerate(instance) 

400 if index not in evaluated_item_indexes 

401 ] 

402 if unevaluated_items: 

403 error = "Unevaluated items are not allowed (%s %s unexpected)" 

404 yield ValidationError(error % extras_msg(unevaluated_items)) 

405 

406 

407def unevaluatedProperties(validator, unevaluatedProperties, instance, schema): 

408 if not validator.is_type(instance, "object"): 

409 return 

410 evaluated_keys = find_evaluated_property_keys_by_schema( 

411 validator, instance, schema, 

412 ) 

413 unevaluated_keys = [] 

414 for property in instance: 

415 if property not in evaluated_keys: 

416 for _ in validator.descend( 

417 instance[property], 

418 unevaluatedProperties, 

419 path=property, 

420 schema_path=property, 

421 ): 

422 # FIXME: Include context for each unevaluated property 

423 # indicating why it's invalid under the subschema. 

424 unevaluated_keys.append(property) # noqa: PERF401 

425 

426 if unevaluated_keys: 

427 if unevaluatedProperties is False: 

428 error = "Unevaluated properties are not allowed (%s %s unexpected)" 

429 extras = sorted(unevaluated_keys, key=str) 

430 yield ValidationError(error % extras_msg(extras)) 

431 else: 

432 error = ( 

433 "Unevaluated properties are not valid under " 

434 "the given schema (%s %s unevaluated and invalid)" 

435 ) 

436 yield ValidationError(error % extras_msg(unevaluated_keys)) 

437 

438 

439def prefixItems(validator, prefixItems, instance, schema): 

440 if not validator.is_type(instance, "array"): 

441 return 

442 

443 for (index, item), subschema in zip(enumerate(instance), prefixItems): 

444 yield from validator.descend( 

445 instance=item, 

446 schema=subschema, 

447 schema_path=index, 

448 path=index, 

449 )