Test Failed
Push — master ( 3849ae...191233 )
by Dominik
07:25
created

_query_compiling()   F

Complexity

Conditions 12

Size

Total Lines 70

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 156

Importance

Changes 11
Bugs 0 Features 0
Metric Value
cc 12
c 11
b 0
f 0
dl 0
loc 70
ccs 0
cts 5
cp 0
crap 156
rs 2.4217

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like _query_compiling() 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
# ~*~ coding: utf-8 ~*~
2
#-
3
# OSMAlchemy - OpenStreetMap to SQLAlchemy bridge
4
# Copyright (c) 2016 Dominik George <[email protected]>
5
# Copyright (c) 2016 Eike Tim Jesinghaus <[email protected]>
6
#
7
# Permission is hereby granted, free of charge, to any person obtaining a copy
8
# of this software and associated documentation files (the "Software"), to deal
9
# in the Software without restriction, including without limitation the rights
10
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
# copies of the Software, and to permit persons to whom the Software is
12
# furnished to do so, subject to the following conditions:
13
#
14
# The above copyright notice and this permission notice shall be included in all
15
# copies or substantial portions of the Software.
16
#
17
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
# SOFTWARE.
24
#
25
# Alternatively, you are free to use OSMAlchemy under Simplified BSD, The
26
# MirOS Licence, GPL-2+, LGPL-2.1+, AGPL-3+ or the same terms as Python
27
# itself.
28 1
29
""" Trigger code for live OSMAlchemy/Overpass integration. """
30 1
31 1
import datetime
32 1
from sqlalchemy import inspect
0 ignored issues
show
Unused Code introduced by
Unused inspect imported from sqlalchemy
Loading history...
33 1
from sqlalchemy.event import listens_for
34 1
from sqlalchemy.orm import Query
35
from weakref import WeakSet
0 ignored issues
show
introduced by
standard import "from weakref import WeakSet" comes before "from sqlalchemy import inspect"
Loading history...
36 1
37 1
from .util.db import _import_osm_xml
38
from .util.online import (_get_elements_by_query, _where_to_tree,
39 1
                          _trees_to_overpassql, _normalise_overpassql,
40
                          _get_single_element_by_id)
41
42
def _generate_triggers(osmalchemy, osmcachedquery, maxage=60*60*24):
43
    """ Generates the triggers for online functionality.
44
45
      osmalchemy - reference to the OSMAlchemy instance to be configured
46
      maxage - maximum age of objects before they are updated online, in seconds
47
    """
48
49
    _visited_queries = WeakSet()
50
51
    @listens_for(osmalchemy.node, "load")
52
    @listens_for(osmalchemy.way, "load")
53
    @listens_for(osmalchemy.relation, "load")
54
    def _instance_loading(target, context, _=None):
0 ignored issues
show
Unused Code introduced by
The variable _instance_loading seems to be unused.
Loading history...
55
        # Get query session
56
        session = context.session
57
58
        # Skip if the session was in a trigger before
59
        # Prevents recursion in import code
60
        if hasattr(session, "_osmalchemy_in_trigger"):
61
            return
62
63
        # Check whether object needs to be refreshed
64
        updated = target.osmalchemy_updated
65
        timediff = datetime.datetime.now() - updated
66
        if timediff.total_seconds() < maxage:
67
            return
68
69
        # Determine OSM element type and id
70
        type_ = target.__class__.__name__[3:].lower()
71
        id_ = target.id
72
73
        # Guard against broken objects without an id
74
        if id_ is None:
75
            return
76
77
        # Get object by id as XML
78
        xml = _get_single_element_by_id(osmalchemy._overpass, type_, id_)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _overpass was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
79
80
        # Import data
81
        session._osmalchemy_in_trigger = True
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _osmalchemy_in_trigger was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
82
        _import_osm_xml(osmalchemy, session, xml)
83
        del session._osmalchemy_in_trigger
84
85
    @listens_for(Query, "before_compile")
86
    def _query_compiling(query):
0 ignored issues
show
Unused Code introduced by
The variable _query_compiling seems to be unused.
Loading history...
87
        # Get the session associated with the query:
88
        session = query.session
89
90
        # Skip if the session was in a trigger before
91
        # Prevents recursion in import code
92
        if hasattr(session, "_osmalchemy_in_trigger"):
93
            return
94
95
        # Prevent recursion by skipping already-seen queries
96
        if query in _visited_queries:
97
            return
98
        else:
99
            _visited_queries.add(query)
100
101
        # Check whether this query affects our model
102
        affected_models = set([c["type"] for c in query.column_descriptions])
103
        our_models = set([osmalchemy.node, osmalchemy.way,  osmalchemy.relation,
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
Loading history...
104
                          osmalchemy.element])
105
        if affected_models.isdisjoint(our_models):
106
            # None of our models is affected
107
            return
108
109
        # Check whether this query filters elements
110
        # Online update will only run on a specified set, not all data
111
        if query.whereclause is None:
112
            # No filters
113
            return
114
115
        # Analyse where clause looking for all looked-up fields
116
        trees = {}
117
        for target in our_models.intersection(affected_models):
118
            # Build expression trees first
119
            tree = _where_to_tree(query.whereclause, target)
120
            if not tree is None:
121
                trees[target.__name__] = tree
122
123
        # Bail out if no relevant trees were built
124
        if not trees:
125
            return
126
127
        # Compile to OverpassQL
128
        oql = _trees_to_overpassql(trees)
129
130
        # Look up query in cache
131
        hashed_oql = hash(_normalise_overpassql(oql))
132
        cached_query = session.query(osmcachedquery).filter_by(oql_hash=hashed_oql).scalar()
133
        # Check age if cached query was found
134
        if cached_query:
135
            timediff = datetime.datetime.now() - cached_query.oql_queried
136
            if timediff.seconds < maxage:
137
                # Return and do nothing if query was run recently
138
                return
139
140
        # Run query online
141
        xml = _get_elements_by_query(osmalchemy._overpass, oql)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _overpass was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
142
143
        # Import data
144
        session._osmalchemy_in_trigger = True
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _osmalchemy_in_trigger was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
145
        _import_osm_xml(osmalchemy, session, xml)
146
        del session._osmalchemy_in_trigger
147
148
        # Store or update query time
149
        if not cached_query:
150
            cached_query = osmcachedquery()
151
            cached_query.oql_hash = hashed_oql
152
        cached_query.oql_queried = datetime.datetime.now()
153
        session.add(cached_query)
154
        session.commit()
155