conftest.map_graph_model()   D
last analyzed

Complexity

Conditions 13

Size

Total Lines 48
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 34
nop 2
dl 0
loc 48
rs 4.2
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like conftest.map_graph_model() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import ast
2
import hashlib
3
import inspect
4
import operator
5
import pickle
6
import random
7
from _ast import AST
8
from collections.abc import Iterable
9
10
import faker
11
import pytest
12
13
import graphinate
14
15
16
@pytest.fixture
17
def country_count():
18
    return random.randint(1, 10)
19
20
21
@pytest.fixture
22
def city_count():
23
    return random.randint(20, 40)
24
25
26
def _ast_nodes(parsed_asts: Iterable[AST]):
27
    for item in parsed_asts:
28
        if not isinstance(item, ast.Load):
29
            yield item
30
            yield from _ast_nodes(ast.iter_child_nodes(item))
31
32
33 View Code Duplication
def _ast_edge(parsed_ast: AST):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
34
    for child_ast in ast.iter_child_nodes(parsed_ast):
35
        if not isinstance(child_ast, ast.Load):
36
            edge = {'source': parsed_ast, 'target': child_ast}
37
            edge_types = (field_name for field_name, value in ast.iter_fields(parsed_ast) if
0 ignored issues
show
introduced by
The variable field_name does not seem to be defined for all execution paths.
Loading history...
38
                          child_ast == value or (child_ast in value if isinstance(value, list) else False))
39
            edge_type = next(edge_types, None)
40
            if edge_type:
41
                edge['type'] = edge_type
42
            yield edge
43
            yield from _ast_edge(child_ast)
44
45
46 View Code Duplication
@pytest.fixture
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
47
def ast_graph_model():
48
    graph_model = graphinate.model(name='AST Graph')
49
50
    root_ast_node = ast.parse(inspect.getsource(graphinate.builders.D3Builder))
51
52
    def node_type(ast_node):
53
        return ast_node.__class__.__name__
54
55
    def node_label(ast_node) -> str:
56
        label = ast_node.__class__.__name__
57
58
        for field_name in ('name', 'id'):
59
            if field_name in ast_node._fields:
60
                label = f"{label}\n{field_name}: {operator.attrgetter(field_name)(ast_node)}"
61
62
        return label
63
64
    def key(value):
65
        # noinspection InsecureHash
66
        return hashlib.shake_128(pickle.dumps(value)).hexdigest(20)
67
68
    def endpoint(value, endpoint_name):
69
        return key(value[endpoint_name])
70
71
    def source(value):
72
        return endpoint(value, 'source')
73
74
    def target(value):
75
        return endpoint(value, 'target')
76
77
    @graph_model.node(type_=node_type, key=key, label=node_label, unique=True)
78
    def ast_node(**kwargs):
79
        yield from _ast_nodes([root_ast_node])
80
81
    @graph_model.edge(type_='edge', source=source, target=target, label=operator.itemgetter('type'))
82
    def ast_edge(**kwargs):
83
        yield from _ast_edge(root_ast_node)
84
85
    return graph_model
86
87
88
@pytest.fixture
89
def map_graph_model(country_count, city_count):
90
    country_ids = {str(c): None for c in range(1, country_count + 1)}
91
    city_ids = {str(c): random.choice(list(country_ids.keys())) for c in range(1, city_count + 1)}
92
93
    graph_model = graphinate.model(name='Map')
94
95
    faker.Faker.seed(0)
96
    fake = faker.Faker()
97
98
    def country_node_label(value):
99
        return fake.country()
100
101
    def city_node_label(value):
102
        return fake.city()
103
104
    @graph_model.node(label=country_node_label, unique=False)
105
    def country(country_id=None, **kwargs):
106
107
        if country_id and country_id in country_ids:
108
            yield country_id
109
        else:
110
            yield from country_ids
111
112
    @graph_model.node(parent_type='country', label=city_node_label, unique=False)
113
    def city(country_id=None, city_id=None, **kwargs):
114
115
        if country_id is None and city_id is None:
116
            yield from city_ids.keys()
117
118
        if country_id is None and city_id is not None and city_id in city_ids:
119
            yield city_id
120
121
        if city_id is not None and country_id is not None and city_ids.get(city_id) == country_id:
122
            yield city_id
123
124
        if country_id is not None and city_id is None:
125
            yield from (k for k, v in city_ids.items() if v == country_id)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable k does not seem to be defined.
Loading history...
126
127
    @graph_model.node(type_=operator.itemgetter('sex'),
128
                      parent_type='city',
129
                      unique= False,
130
                      key=operator.itemgetter('username'),
131
                      label=operator.itemgetter('name'))
132
    def person(country_id=None, city_id=None, person_id=None, **kwargs):
133
        yield fake.profile()
134
135
    return country_count, city_count, graph_model
136
137
138
@pytest.fixture
139
def octagonal_graph_model():
140
    graph_model = graphinate.model(name="Octagonal Graph")
141
    number_of_sides = 8
142
143
    # Register edges supplier function
144
    @graph_model.edge()
145
    def edge():
146
        for i in range(number_of_sides):
147
            yield {'source': i, 'target': i + 1}
148
        yield {'source': number_of_sides, 'target': 0}
149
150
    return graph_model
151
152
153
@pytest.fixture
154
def graphql_query():
155
    return """
156
    query Graph {
157
      graph {
158
        name
159
        nodeTypeCounts {
160
          name
161
          value
162
        }
163
        edgeTypeCounts {
164
          name
165
          value
166
        }
167
        created
168
        nodeCount
169
        edgeCount
170
        size
171
        order
172
        radius
173
        diameter
174
        averageDegree
175
        hash
176
      }
177
      nodes {
178
        id
179
        ...ElementDetails
180
        neighbors {id type label}
181
        children: neighbors(children: true) {id type label}
182
        edges {id type label}
183
      }
184
      edges {
185
        source {id ...ElementDetails}
186
        target {id ...ElementDetails}
187
        ...ElementDetails
188
        weight
189
      }
190
    }
191
192
    fragment ElementDetails on GraphElement {
193
      label
194
      type
195
      label
196
      color
197
      created
198
      updated
199
    }
200
    """
201