Completed
Push — master ( caabd8...c07396 )
by Oleksandr
01:11
created

il2fb.parsers.mission.MissionParser._raise_error()   A

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1
Metric Value
cc 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
1
# -*- coding: utf-8 -*-
2
3 1
import six
4 1
import sys
5
6 1
from .exceptions import MissionParsingError
7 1
from .sections.main import MainSectionParser
8 1
from .sections.season import SeasonSectionParser
9 1
from .sections.weather import WeatherSectionParser
10 1
from .sections.respawn_time import RespawnTimeSectionParser
11 1
from .sections.mds import MDSSectionParser
12 1
from .sections.mds_scouts import MDSScoutsSectionParser
13 1
from .sections.chiefs import ChiefsSectionParser
14 1
from .sections.chief_road import ChiefRoadSectionParser
15 1
from .sections.nstationary import NStationarySectionParser
16 1
from .sections.buildings import BuildingsSectionParser
17 1
from .sections.target import TargetSectionParser
18 1
from .sections.born_place import BornPlaceSectionParser
19 1
from .sections.born_place_aircrafts import BornPlaceAircraftsSectionParser
20 1
from .sections.born_place_air_forces import BornPlaceAirForcesSectionParser
21 1
from .sections.static_camera import StaticCameraSectionParser
22 1
from .sections.front_marker import FrontMarkerSectionParser
23 1
from .sections.rocket import RocketSectionParser
24 1
from .sections.wing import WingSectionParser
25 1
from .sections.flight_info import FlightInfoSectionParser
26 1
from .sections.flight_route import FlightRouteSectionParser
27 1
from .utils import move_if_present, set_if_present, strip_comments
28
29
30 1
class MissionParser(object):
31
    """
32
    Parses a whole mission file.
33
    View :ref:`detailed description <file-parser>`.
34
    """
35
36 1
    def __init__(self):
37 1
        self.parsers = [
38
            MainSectionParser(),
39
            SeasonSectionParser(),
40
            WeatherSectionParser(),
41
            RespawnTimeSectionParser(),
42
            MDSSectionParser(),
43
            MDSScoutsSectionParser(),
44
            ChiefsSectionParser(),
45
            ChiefRoadSectionParser(),
46
            NStationarySectionParser(),
47
            BuildingsSectionParser(),
48
            TargetSectionParser(),
49
            BornPlaceSectionParser(),
50
            BornPlaceAircraftsSectionParser(),
51
            BornPlaceAirForcesSectionParser(),
52
            StaticCameraSectionParser(),
53
            FrontMarkerSectionParser(),
54
            RocketSectionParser(),
55
            WingSectionParser(),
56
            FlightRouteSectionParser(),
57
        ]
58 1
        self.flight_info_parser = FlightInfoSectionParser()
59
60 1
    def parse(self, mission):
61 1
        if isinstance(mission, six.string_types):
62 1
            with open(mission, 'r') as f:
63 1
                return self.parse_stream(f)
64
        else:
65 1
            return self.parse_stream(mission)
66
67 1
    def parse_stream(self, sequence):
68 1
        self._current_parser = None
69 1
        self.data = {}
70
71 1
        for i, line in enumerate(sequence):
72 1
            line = strip_comments(line)
73 1
            if self.is_section_name(line):
74 1
                self._finalize_current_parser()
75 1
                section_name = self.get_section_name(line)
76 1
                self._current_parser = self._get_parser(section_name)
77 1
            elif self._current_parser:
78 1
                self._try_to_parse_line(i, line)
79
80 1
        self._finalize_current_parser()
81 1
        return self._clean()
82
83 1
    @staticmethod
84
    def is_section_name(line):
85 1
        return line.startswith('[') and line.endswith(']')
86
87 1
    @staticmethod
88
    def get_section_name(line):
89 1
        return line.strip('[]')
90
91 1
    def _get_parser(self, section_name):
92 1
        parser = self.flight_info_parser
93 1
        flights = self.data.get('flights')
94
95 1
        if flights is not None and parser.start(section_name):
96 1
            return parser
97
98 1
        for parser in self.parsers:
99 1
            if parser.start(section_name):
100 1
                return parser
101
102 1
        return None
103
104 1
    def _finalize_current_parser(self):
105 1
        if not self._current_parser:
106 1
            return
107 1
        try:
108 1
            data = self._current_parser.stop()
109 1
        except Exception:
110 1
            error_type, original_msg, traceback = sys.exc_info()
111 1
            msg = (
112
                "{0} during finalization of \"{1}\": {2}"
113
                .format(error_type.__name__,
114
                        self._current_parser.__class__.__name__,
115
                        original_msg))
116 1
            self._raise_error(msg, traceback)
117
        else:
118 1
            self.data.update(data)
119
        finally:
120 1
            self._current_parser = None
121
122 1
    def _try_to_parse_line(self, line_number, line):
123 1
        try:
124 1
            self._current_parser.parse_line(line)
125 1
        except Exception:
126 1
            error_type, original_msg, traceback = sys.exc_info()
127 1
            msg = (
128
                "{0} in line #{1} (\"{2}\"): {3}"
129
                .format(error_type.__name__, line_number, line, original_msg))
130 1
            self._raise_error(msg, traceback)
131
132 1
    @staticmethod
133
    def _raise_error(message, traceback):
134 1
        error = MissionParsingError(message)
135 1
        six.reraise(MissionParsingError, error, traceback)
136
137 1
    def _clean(self):
138 1
        result = {}
139
140 1
        move_if_present(result, self.data, 'location_loader')
141 1
        move_if_present(result, self.data, 'player')
142 1
        move_if_present(result, self.data, 'targets')
143
144 1
        set_if_present(result, 'conditions', self._get_conditions())
145 1
        set_if_present(result, 'objects', self._get_objects())
146
147 1
        return result
148
149 1
    def _get_conditions(self):
150 1
        result = {}
151
152 1
        set_if_present(result, 'time_info', self._get_time_info())
153 1
        set_if_present(result, 'meteorology', self._get_meteorology())
154 1
        set_if_present(result, 'scouting', self._get_scouting())
155
156 1
        move_if_present(result, self.data, 'respawn_time')
157
158 1
        if 'conditions' in self.data:
159 1
            conditions = self.data['conditions']
160
161 1
            move_if_present(result, conditions, 'radar')
162 1
            move_if_present(result, conditions, 'communication')
163 1
            move_if_present(result, conditions, 'home_bases')
164 1
            move_if_present(result, conditions, 'crater_visibility_muptipliers')
165
166 1
        return result
167
168 1
    def _get_time_info(self):
169 1
        result = {}
170
171 1
        move_if_present(result, self.data, 'date')
172 1
        if 'time' in self.data:
173 1
            result.update({
174
                'time': self.data['time']['value'],
175
                'is_fixed': self.data['time']['is_fixed'],
176
            })
177
178 1
        return result
179
180 1
    def _get_meteorology(self):
181 1
        result = {}
182
183 1
        move_if_present(result, self.data, 'weather', 'weather_conditions')
184 1
        move_if_present(result, self.data, 'cloud_base')
185
186 1
        if 'weather' in self.data:
187 1
            result.update(self.data.pop('weather'))
188
189 1
        return result
190
191 1
    def _get_scouting(self):
192 1
        result = {}
193
194 1
        try:
195 1
            conditions = self.data['conditions'].pop('scouting')
196 1
            result.update(conditions)
197 1
        except KeyError:
198
            pass
199
200 1
        keys = filter(
201
            lambda x: x.startswith(MDSScoutsSectionParser.output_prefix),
202
            self.data.keys()
203
        )
204 1
        scouts = {
205
            self.data[key]['belligerent']: self.data[key]['aircrafts']
206
            for key in keys
207
        }
208 1
        set_if_present(result, 'scouts', scouts)
209
210 1
        return result
211
212 1
    def _get_objects(self):
213 1
        result = {}
214
215 1
        set_if_present(result, 'moving_units', self._get_moving_units())
216 1
        set_if_present(result, 'flights', self._get_flights())
217 1
        set_if_present(result, 'home_bases', self._get_home_bases())
218
219 1
        move_if_present(result, self.data, 'stationary')
220 1
        move_if_present(result, self.data, 'buildings')
221 1
        move_if_present(result, self.data, 'cameras')
222 1
        move_if_present(result, self.data, 'markers')
223 1
        move_if_present(result, self.data, 'rockets')
224
225 1
        return result
226
227 1
    def _get_moving_units(self):
228 1
        units = self.data.pop('moving_units', [])
229 1
        for unit in units:
230 1
            key = "{}{}".format(ChiefRoadSectionParser.output_prefix, unit['id'])
231 1
            unit['route'] = self.data.pop(key, [])
232 1
        return units
233
234 1
    def _get_flights(self):
235 1
        keys = self.data.pop('flights', [])
236 1
        flights = [self.data.pop(key) for key in keys if key in self.data]
237 1
        for flight in flights:
238 1
            key = "{}{}".format(FlightRouteSectionParser.output_prefix, flight['id'])
239 1
            flight['route'] = self.data.pop(key, [])
240 1
        return flights
241
242 1
    def _get_home_bases(self):
243 1
        home_bases = self.data.pop('home_bases', [])
244 1
        for i, home_base in enumerate(home_bases):
245 1
            key = "{}{}".format(BornPlaceAircraftsSectionParser.output_prefix, i)
246 1
            home_base['spawning']['aircraft_limitations']['allowed_aircrafts'] = self.data.pop(key, [])
247
248 1
            key = "{}{}".format(BornPlaceAirForcesSectionParser.output_prefix, i)
249 1
            home_base['spawning']['allowed_air_forces'] = self.data.pop(key, [])
250
        return home_bases
251