Coverage for genschema / comparators / empty.py: 94%

31 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-14 22:23 +0000

1from .template import Comparator, ComparatorResult, ProcessingContext, Resource 

2 

3 

4class EmptyComparator(Comparator): 

5 """ 

6 Добавляет maxItems=0 или maxProperties=0 для полностью пустых массивов/объектов, 

7 а так же minItems=0 или minProperties=0 для полностью НЕ пустых массивов/объектов, 

8 если на данном уровне нет кандидатов из непустых схем или JSON. 

9 """ 

10 

11 name = "empty" 

12 

13 def __init__(self, flag_empty: bool = True, flag_non_empty: bool = True): 

14 self.flag_empty = flag_empty 

15 self.flag_non_empty = flag_non_empty 

16 

17 def can_process(self, ctx: ProcessingContext, env: str, node: dict) -> bool: 

18 t = node.get("type") 

19 return t == "object" or t == "array" 

20 

21 def process(self, ctx: ProcessingContext, env: str, node: dict) -> ComparatorResult: 

22 

23 # Проверяем есть ли непустые кандидаты на этом уровне 

24 def is_nonempty(r: Resource) -> bool: 

25 c = r.content 

26 if isinstance(c, dict): 

27 return bool(c) # не пустой словарь 

28 if isinstance(c, list): 

29 return bool(c) # не пустой список 

30 return True # скаляры считаем непустыми 

31 

32 candidates = [is_nonempty(r) for r in ctx.schemas + ctx.jsons] 

33 

34 if self.flag_empty and not any(candidates): 

35 t = node.get("type") 

36 if t == "object": 

37 return {"maxProperties": 0}, None 

38 elif t == "array": 

39 return {"maxItems": 0}, None 

40 elif self.flag_non_empty and all(candidates): 

41 t = node.get("type") 

42 if t == "object": 

43 return {"minProperties": 1}, None 

44 elif t == "array": 

45 return {"minItems": 1}, None 

46 

47 return None, None