• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bogdandm / json2python-models / 11497710154

24 Oct 2024 10:40AM UTC coverage: 90.904% (-7.2%) from 98.072%
11497710154

Pull #59

github

bkalashnikov
Enable pytest workers
Pull Request #59: Modernize project setup and setup cron action job

2 of 6 new or added lines in 2 files covered. (33.33%)

115 existing lines in 7 files now uncovered.

1479 of 1627 relevant lines covered (90.9%)

4.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.63
/json_to_models/models/structure.py
1
from typing import Dict, Iterable, List, Set, Tuple
5✔
2

3
from . import Index, ModelsStructureType
5✔
4
from .utils import ListEx, PositionsDict
5✔
5
from ..dynamic_typing import BaseType, DOptional, ModelMeta, ModelPtr
5✔
6

7

8
def compose_models(models_map: Dict[str, ModelMeta]) -> ModelsStructureType:
5✔
9
    """
10
    Generate nested sorted models structure for internal usage.
11

12
    :return: List of root models data, Map(child model -> root model) for absolute ref generation
13
    """
14
    root_models = ListEx()
5✔
15
    root_nested_ix = 0
5✔
16
    structure_hash_table: Dict[Index, dict] = {
5✔
17
        key: {
18
            "model": model,
19
            "nested": ListEx(),
20
            "roots": list(extract_root(model)),  # Indexes of root level models
21
        } for key, model in models_map.items()
22
    }
23
    # TODO: Test path_injections
24
    path_injections: Dict[ModelMeta, ModelMeta] = {}
5✔
25

26
    for key, model in models_map.items():
5✔
27
        pointers = list(filter_pointers(model))
5✔
28
        has_root_pointers = len(pointers) != len(model.pointers)
5✔
29
        if not pointers:
5✔
30
            # Root level model
31
            if not has_root_pointers:
5✔
32
                raise Exception(f'Model {model.name} has no pointers')
×
33
            root_models.append(structure_hash_table[key])
5✔
34
        else:
35
            parents = {ptr.parent.index for ptr in pointers}
5✔
36
            struct = structure_hash_table[key]
5✔
37
            # Model is using by other models
38
            if has_root_pointers or len(parents) > 1 and len(struct["roots"]) > 1:
5✔
39
                # Model is using by different root models
40
                try:
5✔
41
                    root_models.insert_before(
5✔
42
                        struct,
43
                        *(structure_hash_table[parent_key] for parent_key in struct["roots"])
44
                    )
45
                except ValueError:
5✔
46
                    root_models.insert(root_nested_ix, struct)
5✔
47
                    root_nested_ix += 1
5✔
48
            elif len(parents) > 1 and len(struct["roots"]) == 1:
5✔
49
                # Model is using by single root model
50
                parent = structure_hash_table[struct["roots"][0]]
5✔
51
                parent["nested"].insert(0, struct)
5✔
52
                path_injections[struct["model"]] = parent["model"]
5✔
53
            else:
54
                # Model is using by only one model
55
                parent = structure_hash_table[next(iter(parents))]
5✔
56
                struct = structure_hash_table[key]
5✔
57
                parent["nested"].append(struct)
5✔
58

59
    return root_models, path_injections
5✔
60

61

62
def compose_models_flat(models_map: Dict[Index, ModelMeta]) -> ModelsStructureType:
5✔
63
    """
64
    Generate flat sorted (by nesting level, ASC) models structure for internal usage.
65

66
    :param models_map: Mapping (model index -> model meta instance).
67
    :return: List of root models data, Map(child model -> root model) for absolute ref generation
68
    """
69
    root_models = ListEx()
5✔
70
    positions: PositionsDict[Index, int] = PositionsDict()
5✔
71
    top_level_models: Set[Index] = set()
5✔
72
    structure_hash_table: Dict[Index, dict] = {
5✔
73
        key: {
74
            "model": model,
75
            "nested": ListEx(),
76
            "roots": list(extract_root(model)),  # Indexes of root level models
77
        } for key, model in models_map.items()
78
    }
79

80
    for key, model in models_map.items():
5✔
81
        pointers = list(filter_pointers(model))
5✔
82
        has_root_pointers = len(pointers) != len(model.pointers)
5✔
83
        if not pointers:
5✔
84
            # Root level model
85
            if not has_root_pointers:
5✔
86
                raise Exception(f'Model {model.name} has no pointers')
×
87
            root_models.insert(positions["root"], structure_hash_table[key])
5✔
88
            top_level_models.add(key)
5✔
89
            positions.update_position("root", PositionsDict.INC)
5✔
90
        else:
91
            parents = {ptr.parent.index for ptr in pointers}
5✔
92
            struct = structure_hash_table[key]
5✔
93
            # Model is using by other models
94
            if has_root_pointers or len(parents) > 1 and len(struct["roots"]) >= 1:
5✔
95
                # Model is using by different root models
96
                if parents & top_level_models:
5✔
97
                    parents.add("root")
5✔
98
                parents_positions = {positions[parent_key] for parent_key in parents
5✔
99
                                     if parent_key in positions}
100
                parents_joined = "#".join(sorted(parents))
5✔
101
                if parents_joined in positions:
5✔
102
                    parents_positions.add(positions[parents_joined])
5✔
103
                pos = max(parents_positions) if parents_positions else len(root_models)
5✔
104
                positions.update_position(parents_joined, pos + 1)
5✔
105
            else:
106
                # Model is using by only one model
107
                parent = next(iter(parents))
5✔
108
                pos = positions.get(parent, len(root_models))
5✔
109
                positions.update_position(parent, pos + 1)
5✔
110
            positions.update_position(key, pos + 1)
5✔
111
            root_models.insert(pos, struct)
5✔
112

113
    return root_models, {}
5✔
114

115

116
def filter_pointers(model: ModelMeta) -> Iterable[ModelPtr]:
5✔
117
    """
118
    Return iterator over pointers with not None parent
119
    """
120
    return (ptr for ptr in model.pointers if ptr.parent)
5✔
121

122

123
def extract_root(model: ModelMeta) -> Set[Index]:
5✔
124
    """
125
    Return set of indexes of root models that are use given `model` directly or through another nested model.
126
    """
127
    seen: Set[Index] = set()
5✔
128
    nodes: List[ModelPtr] = list(filter_pointers(model))
5✔
129
    roots: Set[Index] = set()
5✔
130
    while nodes:
5✔
131
        node = nodes.pop()
5✔
132
        seen.add(node.type.index)
5✔
133
        filtered = list(filter_pointers(node.parent))
5✔
134
        nodes.extend(ptr for ptr in filtered if ptr.type.index not in seen)
5✔
135
        if not filtered:
5✔
136
            roots.add(node.parent.index)
5✔
137
    return roots
5✔
138

139

140
def sort_fields(model_meta: ModelMeta, unicode_fix=False) -> Tuple[List[str], List[str]]:
5✔
141
    """
142
    Split fields into required and optional groups
143

144
    :return: two list of fields names: required fields, optional fields
145
    """
146
    fields = model_meta.type
5✔
147
    required = []
5✔
148
    required_2 = []
5✔
149
    optional = []
5✔
150
    for key, meta in fields.items():
5✔
151
        if isinstance(meta, DOptional):
5✔
152
            optional.append(key)
5✔
153
        elif unicode_fix and isinstance(meta, BaseType) and any(
5✔
154
                isinstance(node, ModelMeta)
155
                for node in meta.iter_child()
156
        ):
UNCOV
157
            required_2.append(key)
×
158
        else:
159
            required.append(key)
5✔
160
    return required + required_2, optional
5✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc