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

243 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:51 +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(sorted(extras, key=str))) 

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 extra = total - prefix 

67 if extra <= 0: 

68 return 

69 

70 if items is False: 

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

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

73 yield ValidationError( 

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

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

76 ) 

77 else: 

78 for index in range(prefix, total): 

79 yield from validator.descend( 

80 instance=instance[index], 

81 schema=items, 

82 path=index, 

83 ) 

84 

85 

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

87 if not equal(instance, const): 

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

89 

90 

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

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

93 return 

94 

95 matches = 0 

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

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

98 

99 for each in instance: 

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

101 matches += 1 

102 if matches > max_contains: 

103 yield ValidationError( 

104 "Too many items match the given schema " 

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

106 validator="maxContains", 

107 validator_value=max_contains, 

108 ) 

109 return 

110 

111 if matches < min_contains: 

112 if not matches: 

113 yield ValidationError( 

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

115 "matching the given schema", 

116 ) 

117 else: 

118 yield ValidationError( 

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

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

121 validator="minContains", 

122 validator_value=min_contains, 

123 ) 

124 

125 

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

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

128 return 

129 

130 if instance <= minimum: 

131 yield ValidationError( 

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

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

134 ) 

135 

136 

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

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

139 return 

140 

141 if instance >= maximum: 

142 yield ValidationError( 

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

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

145 ) 

146 

147 

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

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

150 return 

151 

152 if instance < minimum: 

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

154 yield ValidationError(message) 

155 

156 

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

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

159 return 

160 

161 if instance > maximum: 

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

163 yield ValidationError(message) 

164 

165 

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

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

168 return 

169 

170 if isinstance(dB, float): 

171 quotient = instance / dB 

172 try: 

173 failed = int(quotient) != quotient 

174 except OverflowError: 

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

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

177 # raises an error. 

178 # 

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

180 # exact and cannot overflow. The performance is also 

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

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

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

184 # for already-slow enormous integers or Decimals. 

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

186 else: 

187 failed = instance % dB 

188 

189 if failed: 

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

191 

192 

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

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

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

196 

197 

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

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

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

201 

202 

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

204 if ( 

205 uI 

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

207 and not uniq(instance) 

208 ): 

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

210 

211 

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

213 if ( 

214 validator.is_type(instance, "string") 

215 and not re.search(patrn, instance) 

216 ): 

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

218 

219 

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

221 if validator.format_checker is not None: 

222 try: 

223 validator.format_checker.check(instance, format) 

224 except FormatError as error: 

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

226 

227 

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

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

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

231 

232 

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

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

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

236 

237 

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

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

240 return 

241 

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

243 if property not in instance: 

244 continue 

245 

246 for each in dependency: 

247 if each not in instance: 

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

249 yield ValidationError(message) 

250 

251 

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

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

254 return 

255 

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

257 if property not in instance: 

258 continue 

259 yield from validator.descend( 

260 instance, dependency, schema_path=property, 

261 ) 

262 

263 

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

265 if instance == 0 or instance == 1: 

266 unbooled = unbool(instance) 

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

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

269 elif instance not in enums: 

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

271 

272 

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

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

275 

276 

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

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

279 

280 

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

282 types = ensure_list(types) 

283 

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

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

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

287 

288 

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

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

291 return 

292 

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

294 if property in instance: 

295 yield from validator.descend( 

296 instance[property], 

297 subschema, 

298 path=property, 

299 schema_path=property, 

300 ) 

301 

302 

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

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

305 return 

306 for property in required: 

307 if property not in instance: 

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

309 

310 

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

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

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

314 

315 

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

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

318 return 

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

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

321 

322 

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

324 for index, subschema in enumerate(allOf): 

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

326 

327 

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

329 all_errors = [] 

330 for index, subschema in enumerate(anyOf): 

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

332 if not errs: 

333 break 

334 all_errors.extend(errs) 

335 else: 

336 yield ValidationError( 

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

338 context=all_errors, 

339 ) 

340 

341 

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

343 subschemas = enumerate(oneOf) 

344 all_errors = [] 

345 for index, subschema in subschemas: 

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

347 if not errs: 

348 first_valid = subschema 

349 break 

350 all_errors.extend(errs) 

351 else: 

352 yield ValidationError( 

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

354 context=all_errors, 

355 ) 

356 

357 more_valid = [ 

358 each for _, each in subschemas 

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

360 ] 

361 if more_valid: 

362 more_valid.append(first_valid) 

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

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

365 

366 

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

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

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

370 yield ValidationError(message) 

371 

372 

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

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

375 if "then" in schema: 

376 then = schema["then"] 

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

378 elif "else" in schema: 

379 else_ = schema["else"] 

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

381 

382 

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

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

385 return 

386 evaluated_item_indexes = find_evaluated_item_indexes_by_schema( 

387 validator, instance, schema, 

388 ) 

389 unevaluated_items = [ 

390 item for index, item in enumerate(instance) 

391 if index not in evaluated_item_indexes 

392 ] 

393 if unevaluated_items: 

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

395 yield ValidationError(error % extras_msg(unevaluated_items)) 

396 

397 

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

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

400 return 

401 evaluated_keys = find_evaluated_property_keys_by_schema( 

402 validator, instance, schema, 

403 ) 

404 unevaluated_keys = [] 

405 for property in instance: 

406 if property not in evaluated_keys: 

407 for _ in validator.descend( 

408 instance[property], 

409 unevaluatedProperties, 

410 path=property, 

411 schema_path=property, 

412 ): 

413 # FIXME: Include context for each unevaluated property 

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

415 unevaluated_keys.append(property) 

416 

417 if unevaluated_keys: 

418 if unevaluatedProperties is False: 

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

420 extras = sorted(unevaluated_keys, key=str) 

421 yield ValidationError(error % extras_msg(extras)) 

422 else: 

423 error = ( 

424 "Unevaluated properties are not valid under " 

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

426 ) 

427 yield ValidationError(error % extras_msg(unevaluated_keys)) 

428 

429 

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

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

432 return 

433 

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

435 yield from validator.descend( 

436 instance=item, 

437 schema=subschema, 

438 schema_path=index, 

439 path=index, 

440 )