コード例 #1
0
                def validate_arguments() -> bool:
                    def validate_parameterization_arg(i, arg) -> bool:
                        try:
                            light_param_def = get_parsed_light(
                                light_name).light_param_def
                            if (arg in light_param_def and list(
                                    get_overload_column_info(
                                        overload_type).values())[i]):
                                return True
                        except KeyError:
                            return False
                        else:
                            if ((arg == "NOOP" or arg.startswith("sim/"))
                                    and i == len(light_args) - 1):
                                return True
                            elif re.match("-?\d+(\.\d+)?", arg):
                                return True
                            else:
                                return False

                    prev_logger_errors = len(logger.findErrors())
                    for i, arg in enumerate(light_args):
                        if not validate_parameterization_arg(i, arg):
                            logger.error(
                                f"{line_num}, '{light_name}', arg #{i+1}: ('{arg}')"
                                f" is not a correctly formatted number or is invalid"
                            )
                            continue

                    return not (len(logger.findErrors()) - prev_logger_errors)
コード例 #2
0
    def test_scenery_glass_illegal(self):
        filename = 'test_scenery_glass_illegal'

        xplaneFile = xplane_file.createFileFromBlenderLayerIndex(7)
        out = xplaneFile.write()

        self.assertEqual(len(logger.findErrors()), 1)
        logger.clearMessages()
コード例 #3
0
    def test_export(self):
        filename = 'test_IST_2Mats_VarSPEC'

        xplaneFile = xplane_file.createFileFromBlenderLayerIndex(0)
        out = xplaneFile.write()

        self.assertEquals(len(logger.findErrors()),
                          self.expected_logger_errors)
コード例 #4
0
    def test_export(self):
        filename = 'test_SSO_IllegalUsePanelTex'

        xplaneFile = xplane_file.createFileFromBlenderLayerIndex(0)
        out = xplaneFile.write()

        self.assertEquals(len(logger.findErrors()),
                          self.expected_logger_errors)
コード例 #5
0
    def test_export(self):
        filename = 'test_SSO_2incompatibleDraped_Mats'

        xplaneFile = xplane_file.createFileFromBlenderLayerIndex(0)
        out = xplaneFile.write()

        self.assertEquals(len(logger.findErrors()),
                          self.expected_logger_errors)
コード例 #6
0
    def test_scenery_glass_illegal(self):
        filename = 'test_scenery_glass_illegal'

        xplaneFile = xplane_file.createFileFromBlenderLayerIndex(7)
        out = xplaneFile.write()

        self.assertEqual(len(logger.findErrors()), 1)
        logger.clearMessages()
コード例 #7
0
ファイル: __init__.py プロジェクト: bgersten/XPlane2Blender
 def assertLoggerErrors(self, expected_logger_errors: int) -> None:
     """
     Asserts the logger has some number of errors, then clears the logger
     of all messages
     """
     try:
         found_errors = len(logger.findErrors())
         self.assertEqual(found_errors, expected_logger_errors)
     except AssertionError as e:
         raise AssertionError(
             f"Expected {expected_logger_errors} logger errors, got {found_errors}"
         ) from None
     else:
         logger.clearMessages()
コード例 #8
0
ファイル: __init__.py プロジェクト: xrotors/XPlane2Blender
 def assertLoggerErrors(self, expected_logger_errors):
     self.assertEqual(len(logger.findErrors()), expected_logger_errors)
     logger.clearMessages()
コード例 #9
0
    def test_no_material(self):
        xplaneFile = xplane_file.createFileFromBlenderLayerIndex(0)
        out = xplaneFile.write()

        self.assertEquals(len(logger.findErrors()),
                          self.expected_logger_errors)
コード例 #10
0
 def test_norm_met_off_two_drap_scen(self):
     expected_logger_errors = 1
     #"test_norm_met_off_two_drap_scen"
     out = xplane_file.createFileFromBlenderLayerIndex(3).write()
     self.assertEqual(len(logger.findErrors()), expected_logger_errors)
     logger.clearMessages()
コード例 #11
0
ファイル: __init__.py プロジェクト: der-On/XPlane2Blender
 def assertLoggerErrors(self, expected_logger_errors):
     self.assertEqual(len(logger.findErrors()), expected_logger_errors)
     logger.clearMessages()
コード例 #12
0
 def test_glass_2_mats_conflict(self):
     xplaneFile = xplane_file.createFileFromBlenderLayerIndex(8)
     out = xplaneFile.write()
     
     self.assertEqual(len(logger.findErrors()), 1)
     logger.clearMessages()
コード例 #13
0
    def test_scenery_glass_illegal(self):
        filename = 'test_scenery_glass_illegal'

        out = self.exportLayer(7)
        self.assertEqual(len(logger.findErrors()), 1)
        logger.clearMessages()
コード例 #14
0
    def test_export(self):
        xplaneFile = xplane_file.createFileFromBlenderLayerIndex(0)
        out = xplaneFile.write()

        self.assertEquals(len(logger.findErrors()), 1)
コード例 #15
0
 def test_norm_met_off_two_drap_scen(self):
     expected_logger_errors = 1
                                                                    #"test_norm_met_off_two_drap_scen"
     out = xplane_file.createFileFromBlenderLayerIndex(3).write()
     self.assertEqual(len(logger.findErrors()), expected_logger_errors)
     logger.clearMessages()
コード例 #16
0
 def test_glass_2_mats_conflict(self):
     out = self.exportLayer(8)
     self.assertEqual(len(logger.findErrors()), 1)
     logger.clearMessages()
コード例 #17
0
    def test_glass_2_mats_conflict(self):
        xplaneFile = xplane_file.createFileFromBlenderLayerIndex(8)
        out = xplaneFile.write()

        self.assertEqual(len(logger.findErrors()), 1)
        logger.clearMessages()
コード例 #18
0
def parse_lights_file():
    """
    Parse the lights.txt file, building the dictionary of parsed lights.

    If already parsed, does nothing. Raises OSError or ValueError
    if file not found or content invalid,
    logger errors and warnings will have been collected
    """
    global _parsed_lights_txt_content
    if _parsed_lights_txt_content:
        return

    num_logger_problems = len(logger.findErrors())
    LIGHTS_FILEPATH = os.path.join(xplane_constants.ADDON_RESOURCES_FOLDER,
                                   "lights.txt")
    if not os.path.isfile(LIGHTS_FILEPATH):
        logger.error(
            f"lights.txt file was not found in resource folder {LIGHTS_FILEPATH}"
        )
        raise FileNotFoundError

    def is_allowed_param(p: str) -> bool:
        return (p in {
            "R",
            "G",
            "B",
            "A",
            "SIZE",
            "DX",
            "DY",
            "DZ",
            "WIDTH",
            "FREQ",
            "PHASE",
            "INDEX",
            "DIR_MAG",
        } or p.startswith(("UNUSED", "NEG_ONE", "ZERO", "ONE")))

    with open(LIGHTS_FILEPATH, "r") as f:
        lines = [(line_num, l.strip())
                 for line_num, l in enumerate(f.read().splitlines())
                 if l.startswith((*OVERLOAD_TYPES, "LIGHT_PARAM_DEF"))]

        for line_num, line in lines:
            #print(line)
            try:
                overload_type, light_name, *light_args = line.split()
                if not light_args:
                    raise ValueError
            except ValueError:  # not enough values to unpack
                logger.error(
                    f"{line_num}: Line could not be parsed to '<RECORD_TYPE> <light_name> <params or args list>'"
                )
                continue

            if not re.match("[A-Za-z0-9_]+", light_name):
                logger.error(
                    f"{line_num}: Light name '{light_name}' must be upper/lower case letters, numbers, or underscores only"
                )
                continue

            def get_parsed_light_of_content_dict(
                    light_name: str) -> ParsedLight:
                try:
                    _parsed_lights_txt_content[light_name]
                except KeyError:
                    _parsed_lights_txt_content[light_name] = ParsedLight(
                        light_name)
                finally:
                    return _parsed_lights_txt_content[light_name]

            if overload_type == "LIGHT_PARAM_DEF":
                parsed_light = get_parsed_light_of_content_dict(light_name)
                if parsed_light.light_param_def:
                    logger.error(
                        f"{line_num}: {light_name} cannot have more than one LIGHT_PARAM_DEF"
                    )
                    continue
                light_argc, *light_argv = light_args
                try:
                    light_argc = int(light_argc)
                except ValueError:
                    logger.error(
                        f"{line_num}: Parameter count for '{light_name}''s LIGHT_PARAM_DEF must be an int, is '{light_argc}'"
                    )
                    continue
                else:
                    if not light_argc or not light_argv or (light_argc !=
                                                            len(light_argv)):
                        logger.error(
                            f"{line_num}: '{light_name}''s LIGHT_PARAM_DEF must have a count > 0 and an parameter list of the same length"
                        )
                        continue
                    elif len(set(light_argv)) < len(light_argv):
                        logger.error(
                            f"{line_num}: '{light_name}''s LIGHT_PARAM_DEF has duplicate parameters in it"
                        )
                        continue
                parsed_light.light_param_def = light_argv  # Skip the count
                if parsed_light.light_param_def and any(
                        not is_allowed_param(param)
                        for param in parsed_light.light_param_def):
                    logger.error(
                        f"{line_num}: LIGHT_PARAM_DEF for '{light_name}' contains unknown or invalid parameters: {parsed_light.light_param_def}"
                    )
                    continue
            elif overload_type not in OVERLOAD_TYPES:
                logger.error(
                    f"{line_num}: '{overload_type}' is not a valid OVERLOAD_TYPE."
                )
                continue
            elif len(light_args) < len(
                    get_overload_column_info(overload_type)):
                logger.error(
                    f"{line_num}: Arguments list for '{overload_type} {light_name} {' '.join(light_args)}' is not long enough"
                )
                continue
            elif len(light_args) > len(
                    get_overload_column_info(overload_type)):
                logger.error(
                    f"{line_num}: Arguments list for '{overload_type} {light_name} {' '.join(light_args)}' is too long"
                )
                continue
            else:
                parsed_light = get_parsed_light_of_content_dict(light_name)

                def validate_arguments() -> bool:
                    def validate_parameterization_arg(i, arg) -> bool:
                        try:
                            light_param_def = get_parsed_light(
                                light_name).light_param_def
                            if (arg in light_param_def and list(
                                    get_overload_column_info(
                                        overload_type).values())[i]):
                                return True
                        except KeyError:
                            return False
                        else:
                            if ((arg == "NOOP" or arg.startswith("sim/"))
                                    and i == len(light_args) - 1):
                                return True
                            elif re.match("-?\d+(\.\d+)?", arg):
                                return True
                            else:
                                return False

                    prev_logger_errors = len(logger.findErrors())
                    for i, arg in enumerate(light_args):
                        if not validate_parameterization_arg(i, arg):
                            logger.error(
                                f"{line_num}, '{light_name}', arg #{i+1}: ('{arg}')"
                                f" is not a correctly formatted number or is invalid"
                            )
                            continue

                    return not (len(logger.findErrors()) - prev_logger_errors)

                if not validate_arguments():
                    continue

                def tryfloat(s: str) -> float:
                    try:
                        return float(s)
                    except ValueError:
                        return s

                parsed_light.overloads.append(
                    ParsedLightOverload(overload_type=overload_type,
                                        name=light_name,
                                        arguments=list(
                                            map(tryfloat, light_args))))
                # This is a heuristic/careful reading of X-Plane's light system
                # of what is most likely to give us
                # the correct direction to autocorrect
                rankings = [
                    "SPILL_HW_DIR",  # Most trustworthy
                    "SPILL_HW_FLA",
                    "SPILL_SW",
                    "BILLBOARD_HW",
                    "BILLBOARD_SW",  # Least trustworthy
                    "SPILL_GND",  # Ignored by autocorrector, ranked last
                    "SPILL_GND_REV",  # Ignored by autocorrector, ranked last
                ]

                # Semantically speaking, overloads[0] must ALWAYS be the most trustworthy
                parsed_light.overloads.sort(
                    key=lambda l: rankings.index(l.overload_type))

    for light_name, pl in _parsed_lights_txt_content.items():
        if not pl.overloads:
            logger.error(
                f"Ignoring '{light_name}': Found LIGHT_PARAM_DEF but no valid overloads"
            )
            continue

    _parsed_lights_txt_content = {
        light_name: pl
        for light_name, pl in _parsed_lights_txt_content.items()
        if pl.overloads
    }

    if not _parsed_lights_txt_content:
        logger.error("lights.txt had no valid light records in it")
    if len(logger.findErrors()) - num_logger_problems:
        raise LightsTxtFileParsingError