Completed
Push — master ( 477316...803f9c )
by Michael
08:36
created

awips.dataaccess.ModelSounding   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 241
Duplicated Lines 72.61 %

Importance

Changes 0
Metric Value
wmc 32
eloc 102
dl 175
loc 241
rs 9.84
c 0
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
A _SoundingTimeLayer.levels() 11 11 1
A _SoundingCube.__addItem() 7 7 2
A _SoundingTimeAndLevelLayer.level() 8 8 1
A _SoundingTimeLayer.__getitem__() 6 6 2
A _SoundingTimeAndLevelLayer.time() 8 8 1
A _SoundingCube.__len__() 2 2 1
A _SoundingTimeAndLevelLayer.__init__() 4 4 1
A _SoundingTimeLayer._addItem() 5 5 1
A _SoundingTimeAndLevelLayer.__getitem__() 2 2 1
A _SoundingCube.__init__() 9 9 4
A _SoundingTimeLayer.__init__() 3 3 1
A _SoundingTimeLayer.time() 8 8 1
A _SoundingTimeAndLevelLayer.__len__() 2 2 1
A _SoundingTimeAndLevelLayer.parameters() 8 8 1
A _SoundingTimeAndLevelLayer._addItem() 2 2 1
A _SoundingCube.__getitem__() 2 2 1
A _SoundingTimeLayer.__len__() 2 2 1
A _SoundingCube.times() 8 8 1

5 Functions

Rating   Name   Duplication   Size   Complexity  
A __notStringIter() 0 7 3
A getSounding() 35 35 1
A changeEDEXHost() 0 10 2
A __sanitizeInputs() 0 6 1
A __buildStringList() 0 5 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
#
2
# Classes for retrieving soundings based on gridded data from the Data Access
3
# Framework
4
#
5
#
6
#
7
#     SOFTWARE HISTORY
8
#
9
#    Date            Ticket#       Engineer       Description
10
#    ------------    ----------    -----------    --------------------------
11
#    06/24/15         #4480        dgilling       Initial Creation.
12
#
13
14
from collections import defaultdict
0 ignored issues
show
Unused Code introduced by
Unused defaultdict imported from collections
Loading history...
15
from shapely.geometry import Point
16
17
from awips import DateTimeConverter
0 ignored issues
show
Unused Code introduced by
Unused DateTimeConverter imported from awips
Loading history...
18
from awips.dataaccess import DataAccessLayer
19
20
from dynamicserialize.dstypes.com.raytheon.uf.common.time import DataTime
0 ignored issues
show
Unused Code introduced by
Unused DataTime imported from dynamicserialize.dstypes.com.raytheon.uf.common.time
Loading history...
21
from dynamicserialize.dstypes.com.raytheon.uf.common.dataplugin.level import Level
22
23
24 View Code Duplication
def getSounding(modelName, weatherElements, levels, samplePoint, timeRange=None):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
25
    """
26
    Performs a series of Data Access Framework requests to retrieve a sounding object
27
    based on the specified request parameters.
28
29
    Args:
30
        modelName: the grid model datasetid to use as the basis of the sounding.
31
        weatherElements: a list of parameters to return in the sounding.
32
        levels: a list of levels to sample the given weather elements at
33
        samplePoint: a lat/lon pair to perform the sampling of data at.
34
        timeRange: (optional) a list of times, or a TimeRange to specify
35
        which forecast hours to use. If not specified, will default to all forecast hours.
36
37
    Returns:
38
        A _SoundingCube instance, which acts a 3-tiered dictionary, keyed
39
        by DataTime, then by level and finally by weather element. If no
40
        data is available for the given request parameters, None is returned.
41
42
    """
43
44
    (locationNames, parameters, levels, envelope, timeRange) = \
45
        __sanitizeInputs(modelName, weatherElements, levels, samplePoint, timeRange)
46
47
    requestArgs = { 'datatype'      : 'grid',
0 ignored issues
show
Coding Style introduced by
No space allowed after bracket
Loading history...
48
                    'locationNames' : locationNames,
49
                    'parameters'    : parameters,
50
                    'levels'        : levels,
51
                    'envelope'      : envelope
52
                   }
53
54
    req = DataAccessLayer.newDataRequest(**requestArgs)
55
    response = DataAccessLayer.getGeometryData(req, timeRange)
56
    soundingObject = _SoundingCube(response)
57
58
    return soundingObject
59
60
61
def changeEDEXHost(host):
62
    """
63
    Changes the EDEX host the Data Access Framework is communicating with.
64
65
    Args:
66
            host: the EDEX host to connect to
67
    """
68
69
    if host:
70
        DataAccessLayer.changeEDEXHost(str(host))
71
72
73
def __sanitizeInputs(modelName, weatherElements, levels, samplePoint, timeRange):
74
    locationNames = [str(modelName)]
75
    parameters = __buildStringList(weatherElements)
76
    levels = __buildStringList(levels)
77
    envelope = Point(samplePoint)
78
    return locationNames, parameters, levels, envelope, timeRange
79
80
81
def __buildStringList(param):
82
    if __notStringIter(param):
0 ignored issues
show
unused-code introduced by
Unnecessary "else" after "return"
Loading history...
83
        return [str(item) for item in param]
84
    else:
85
        return [str(param)]
86
87
88
def __notStringIter(iterable):
89
    if not isinstance(iterable, str):
90
        try:
91
            iter(iterable)
92
            return True
93
        except TypeError:
94
            return False
95
96
97 View Code Duplication
class _SoundingCube(object):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
98
    """
99
    The top-level sounding object returned when calling ModelSounding.getSounding.
100
101
    This object acts as a 3-tiered dict which is keyed by time then level
102
    then parameter name. Calling times() will return all valid keys into this
103
    object.
104
    """
105
106
    def __init__(self, geometryDataObjects):
107
        self._dataDict = {}
108
        self._sortedTimes = []
109
        if geometryDataObjects:
110
            for geometryData in geometryDataObjects:
111
                dataTime = geometryData.getDataTime()
112
                level = geometryData.getLevel()
113
                for parameter in geometryData.getParameters():
114
                    self.__addItem(parameter, dataTime, level, geometryData.getNumber(parameter))
115
116
    def __addItem(self, parameter, dataTime, level, value):
117
        timeLayer = self._dataDict.get(dataTime, _SoundingTimeLayer(dataTime))
118
        self._dataDict[dataTime] = timeLayer
119
        timeLayer._addItem(parameter, level, value)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _addItem 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...
120
        if dataTime not in self._sortedTimes:
121
            self._sortedTimes.append(dataTime)
122
            self._sortedTimes.sort()
123
124
    def __getitem__(self, key):
125
        return self._dataDict[key]
126
127
    def __len__(self):
128
        return len(self._dataDict)
129
130
    def times(self):
131
        """
132
        Returns the valid times for this sounding.
133
134
        Returns:
135
            A list containing the valid DataTimes for this sounding in order.
136
        """
137
        return self._sortedTimes
138
139
140 View Code Duplication
class _SoundingTimeLayer(object):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
141
    """
142
    The second-level sounding object returned when calling ModelSounding.getSounding.
143
144
    This object acts as a 2-tiered dict which is keyed by level then parameter
145
    name. Calling levels() will return all valid keys into this
146
    object. Calling time() will return the DataTime for this particular layer.
147
    """
148
149
    def __init__(self, dataTime):
150
        self._dataTime = dataTime
151
        self._dataDict = {}
152
153
    def _addItem(self, parameter, level, value):
154
        asString = str(level)
155
        levelLayer = self._dataDict.get(asString, _SoundingTimeAndLevelLayer(self._dataTime, asString))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (103/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
156
        levelLayer._addItem(parameter, value)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _addItem 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...
157
        self._dataDict[asString] = levelLayer
158
159
    def __getitem__(self, key):
160
        asString = str(key)
161
        if asString in self._dataDict:
162
            return self._dataDict[asString]
163
        else:
164
            raise KeyError("Level " + str(key) + " is not a valid level for this sounding.")
165
166
    def __len__(self):
167
        return len(self._dataDict)
168
169
    def time(self):
170
        """
171
        Returns the DataTime for this sounding cube layer.
172
173
        Returns:
174
            The DataTime for this sounding layer.
175
        """
176
        return self._dataTime
177
178
    def levels(self):
179
        """
180
        Returns the valid levels for this sounding.
181
182
        Returns:
183
            A list containing the valid levels for this sounding in order of
184
            closest to surface to highest from surface.
185
        """
186
        sortedLevels = [Level(level) for level in list(self._dataDict.keys())]
187
        sortedLevels.sort()
188
        return [str(level) for level in sortedLevels]
189
190
191 View Code Duplication
class _SoundingTimeAndLevelLayer(object):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
192
    """
193
    The bottom-level sounding object returned when calling ModelSounding.getSounding.
194
195
    This object acts as a dict which is keyed by parameter name. Calling
196
    parameters() will return all valid keys into this object. Calling time()
197
    will return the DataTime for this particular layer. Calling level() will
198
    return the level for this layer.
199
    """
200
201
    def __init__(self, time, level):
202
        self._time = time
203
        self._level = level
204
        self._parameters = {}
205
206
    def _addItem(self, parameter, value):
207
        self._parameters[parameter] = value
208
209
    def __getitem__(self, key):
210
        return self._parameters[key]
211
212
    def __len__(self):
213
        return len(self._parameters)
214
215
    def level(self):
216
        """
217
        Returns the level for this sounding cube layer.
218
219
        Returns:
220
            The level for this sounding layer.
221
        """
222
        return self._level
223
224
    def parameters(self):
225
        """
226
        Returns the valid parameters for this sounding.
227
228
        Returns:
229
            A list containing the valid parameter names.
230
        """
231
        return list(self._parameters.keys())
232
233
    def time(self):
234
        """
235
        Returns the DataTime for this sounding cube layer.
236
237
        Returns:
238
            The DataTime for this sounding layer.
239
        """
240
        return self._time
241