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

248 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:30 +0000

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 unbool, 

12 uniq, 

13) 

14from jsonschema.exceptions import FormatError, ValidationError 

15 

16 

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

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

19 return 

20 

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

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

23 if re.search(pattern, k): 

24 yield from validator.descend( 

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

26 ) 

27 

28 

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

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

31 return 

32 

33 for property in instance: 

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

35 

36 

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

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

39 return 

40 

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

42 

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

44 for extra in extras: 

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

46 elif not aP and extras: 

47 if "patternProperties" in schema: 

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

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

50 patterns = ", ".join( 

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

52 ) 

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

54 yield ValidationError(error) 

55 else: 

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

57 yield ValidationError(error % extras_msg(extras)) 

58 

59 

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

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

62 return 

63 

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

65 total = len(instance) 

66 if items is False and total > prefix: 

67 message = f"Expected at most {prefix} items, but found {total}" 

68 yield ValidationError(message) 

69 else: 

70 for index in range(prefix, total): 

71 yield from validator.descend( 

72 instance=instance[index], 

73 schema=items, 

74 path=index, 

75 ) 

76 

77 

78def additionalItems(validator, aI, instance, schema): 

79 if ( 

80 not validator.is_type(instance, "array") 

81 or validator.is_type(schema.get("items", {}), "object") 

82 ): 

83 return 

84 

85 len_items = len(schema.get("items", [])) 

86 if validator.is_type(aI, "object"): 

87 for index, item in enumerate(instance[len_items:], start=len_items): 

88 yield from validator.descend(item, aI, path=index) 

89 elif not aI and len(instance) > len(schema.get("items", [])): 

90 error = "Additional items are not allowed (%s %s unexpected)" 

91 yield ValidationError( 

92 error % extras_msg(instance[len(schema.get("items", [])):]), 

93 ) 

94 

95 

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

97 if not equal(instance, const): 

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

99 

100 

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

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

103 return 

104 

105 matches = 0 

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

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

108 

109 for each in instance: 

110 if validator.evolve(schema=contains).is_valid(each): 

111 matches += 1 

112 if matches > max_contains: 

113 yield ValidationError( 

114 "Too many items match the given schema " 

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

116 validator="maxContains", 

117 validator_value=max_contains, 

118 ) 

119 return 

120 

121 if matches < min_contains: 

122 if not matches: 

123 yield ValidationError( 

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

125 "matching the given schema", 

126 ) 

127 else: 

128 yield ValidationError( 

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

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

131 validator="minContains", 

132 validator_value=min_contains, 

133 ) 

134 

135 

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

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

138 return 

139 

140 if instance <= minimum: 

141 yield ValidationError( 

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

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

144 ) 

145 

146 

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

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

149 return 

150 

151 if instance >= maximum: 

152 yield ValidationError( 

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

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

155 ) 

156 

157 

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

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

160 return 

161 

162 if instance < minimum: 

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

164 yield ValidationError(message) 

165 

166 

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

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

169 return 

170 

171 if instance > maximum: 

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

173 yield ValidationError(message) 

174 

175 

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

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

178 return 

179 

180 if isinstance(dB, float): 

181 quotient = instance / dB 

182 try: 

183 failed = int(quotient) != quotient 

184 except OverflowError: 

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

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

187 # raises an error. 

188 # 

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

190 # exact and cannot overflow. The performance is also 

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

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

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

194 # for already-slow enormous integers or Decimals. 

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

196 else: 

197 failed = instance % dB 

198 

199 if failed: 

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

201 

202 

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

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

205 yield ValidationError(f"{instance!r} is too short") 

206 

207 

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

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

210 yield ValidationError(f"{instance!r} is too long") 

211 

212 

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

214 if ( 

215 uI 

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

217 and not uniq(instance) 

218 ): 

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

220 

221 

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

223 if ( 

224 validator.is_type(instance, "string") 

225 and not re.search(patrn, instance) 

226 ): 

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

228 

229 

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

231 if validator.format_checker is not None: 

232 try: 

233 validator.format_checker.check(instance, format) 

234 except FormatError as error: 

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

236 

237 

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

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

240 yield ValidationError(f"{instance!r} is too short") 

241 

242 

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

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

245 yield ValidationError(f"{instance!r} is too long") 

246 

247 

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

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

250 return 

251 

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

253 if property not in instance: 

254 continue 

255 

256 for each in dependency: 

257 if each not in instance: 

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

259 yield ValidationError(message) 

260 

261 

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

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

264 return 

265 

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

267 if property not in instance: 

268 continue 

269 yield from validator.descend( 

270 instance, dependency, schema_path=property, 

271 ) 

272 

273 

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

275 if instance == 0 or instance == 1: 

276 unbooled = unbool(instance) 

277 if all(unbooled != unbool(each) for each in enums): 

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

279 elif instance not in enums: 

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

281 

282 

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

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

285 

286 

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

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

289 

290 

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

292 types = ensure_list(types) 

293 

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

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

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

297 

298 

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

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

301 return 

302 

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

304 if property in instance: 

305 yield from validator.descend( 

306 instance[property], 

307 subschema, 

308 path=property, 

309 schema_path=property, 

310 ) 

311 

312 

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

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

315 return 

316 for property in required: 

317 if property not in instance: 

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

319 

320 

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

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

323 yield ValidationError(f"{instance!r} does not have enough properties") 

324 

325 

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

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

328 return 

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

330 yield ValidationError(f"{instance!r} has too many properties") 

331 

332 

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

334 for index, subschema in enumerate(allOf): 

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

336 

337 

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

339 all_errors = [] 

340 for index, subschema in enumerate(anyOf): 

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

342 if not errs: 

343 break 

344 all_errors.extend(errs) 

345 else: 

346 yield ValidationError( 

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

348 context=all_errors, 

349 ) 

350 

351 

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

353 subschemas = enumerate(oneOf) 

354 all_errors = [] 

355 for index, subschema in subschemas: 

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

357 if not errs: 

358 first_valid = subschema 

359 break 

360 all_errors.extend(errs) 

361 else: 

362 yield ValidationError( 

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

364 context=all_errors, 

365 ) 

366 

367 more_valid = [ 

368 each for _, each in subschemas 

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

370 ] 

371 if more_valid: 

372 more_valid.append(first_valid) 

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

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

375 

376 

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

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

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

380 yield ValidationError(message) 

381 

382 

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

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

385 if "then" in schema: 

386 then = schema["then"] 

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

388 elif "else" in schema: 

389 else_ = schema["else"] 

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

391 

392 

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

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

395 return 

396 evaluated_item_indexes = find_evaluated_item_indexes_by_schema( 

397 validator, instance, schema, 

398 ) 

399 unevaluated_items = [ 

400 item for index, item in enumerate(instance) 

401 if index not in evaluated_item_indexes 

402 ] 

403 if unevaluated_items: 

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

405 yield ValidationError(error % extras_msg(unevaluated_items)) 

406 

407 

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

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

410 return 

411 evaluated_keys = find_evaluated_property_keys_by_schema( 

412 validator, instance, schema, 

413 ) 

414 unevaluated_keys = [] 

415 for property in instance: 

416 if property not in evaluated_keys: 

417 for _ in validator.descend( 

418 instance[property], 

419 unevaluatedProperties, 

420 path=property, 

421 schema_path=property, 

422 ): 

423 # FIXME: Include context for each unevaluated property 

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

425 unevaluated_keys.append(property) 

426 

427 if unevaluated_keys: 

428 if unevaluatedProperties is False: 

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

430 yield ValidationError(error % extras_msg(unevaluated_keys)) 

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 )