Beispiel #1
0
def snip_codes(codes: element.Element) -> Codes:
    wall_codes = codes.xpath('Wall/*/Code')
    window_codes = codes.xpath('Window/*/Code')

    return Codes(
        wall=[node.to_string() for node in wall_codes],
        window=[node.to_string() for node in window_codes],
    )
Beispiel #2
0
    def from_data(
            cls,
            water_heating: element.Element) -> typing.List['WaterHeating']:
        water_heatings = water_heating.xpath(
            "*[self::Primary or self::Secondary]")

        return [cls._from_data(heater) for heater in water_heatings]
Beispiel #3
0
    def from_basement(cls, wall: element.Element, wall_perimeter: float) -> typing.List['BasementWall']:
        interior_wall_sections = wall.xpath('Construction/InteriorAddedInsulation/Composite/Section')
        exterior_wall_sections = wall.xpath('Construction/ExteriorAddedInsulation/Composite/Section')
        pony_wall_sections = wall.xpath('Construction/PonyWallType/Composite/Section')

        try:
            wall_height = wall.get('Measurements/@height', float)
            pony_height = wall.get('Measurements/@ponyWallHeight', float)
        except ElementGetValueError as exc:
            raise InvalidEmbeddedDataTypeError(BasementWall, 'Missing/invalid basement wall height') from exc

        walls = []
        sections = (interior_wall_sections, exterior_wall_sections, pony_wall_sections)

        parsers = (
            lambda section, percentage: BasementWall._from_data(
                section,
                wall_perimeter,
                wall_height,
                WallType.INTERIOR,
                percentage
            ),
            lambda section, percentage: BasementWall._from_data(
                section,
                wall_perimeter,
                wall_height,
                WallType.EXTERIOR,
                percentage
            ),
            lambda section, percentage: BasementWall._from_data(
                section,
                wall_perimeter,
                pony_height,
                WallType.PONY,
                percentage
            )
        )

        for parser, wall_sections in zip(parsers, sections):
            percentages = [wall.attrib.get('percentage') for wall in wall_sections]
            accounted_for = sum(float(percentage) for percentage in percentages if percentage is not None)

            walls.extend([parser(wall, 100-accounted_for) for wall in wall_sections])

        return walls
Beispiel #4
0
    def _from_data(cls,
                   floor: element.Element,
                   construction_type: str,
                   floor_type: FloorType) -> 'BasementFloor':

        length: typing.Optional[float] = None
        width: typing.Optional[float] = None

        try:
            rectangular = floor.get('Measurements/@isRectangular', str) == 'true'
            if rectangular:
                length = floor.get('Measurements/@length', float)
                width = floor.get('Measurements/@width', float)
                perimeter = (2 * length) + (2 * width)
                floor_area = length * width
            else:
                floor_area = floor.get('Measurements/@area', float)
                perimeter = floor.get('Measurements/@perimeter', float)

            nominal_insulation_node = floor.xpath(f'Construction/{construction_type}/@nominalInsulation')
            effective_insulation_node = floor.xpath(f'Construction/{construction_type}/@rValue')

            nominal_insulation = float(nominal_insulation_node[0]) if nominal_insulation_node else None

            effective_insulation = float(effective_insulation_node[0]) if effective_insulation_node else None
        except ValueError as exc:
            raise InvalidEmbeddedDataTypeError(BasementFloor, 'Invalid insulation attribute values') from exc
        except ElementGetValueError as exc:
            raise InvalidEmbeddedDataTypeError(BasementFloor, 'Invalid attributes') from exc

        return BasementFloor(
            floor_type=floor_type,
            rectangular=rectangular,
            nominal_insulation=insulation.Insulation(nominal_insulation)
            if nominal_insulation is not None else None,

            effective_insulation=insulation.Insulation(effective_insulation)
            if effective_insulation is not None else None,

            length=distance.Distance(length) if length is not None else None,
            width=distance.Distance(width) if width is not None else None,
            perimeter=distance.Distance(perimeter),
            floor_area=area.Area(floor_area),
        )
Beispiel #5
0
    def from_data(cls, basement: element.Element) -> 'Basement':
        foundation_type = cls._derive_foundation_type(basement.tag)
        if foundation_type is FoundationType.UNKNOWN:
            raise InvalidEmbeddedDataTypeError(Basement, f'Invalid foundation type: {basement.tag}')

        if foundation_type is FoundationType.BASEMENT:
            floor_from_data = BasementFloor.from_basement
            wall_from_data = BasementWall.from_basement
            header_from_data = BasementHeader.from_data
        elif foundation_type is FoundationType.CRAWLSPACE:
            floor_from_data = BasementFloor.from_crawlspace
            wall_from_data = BasementWall.from_crawlspace
            header_from_data = BasementHeader.from_data
        else:
            floor_from_data = BasementFloor.from_slab
            wall_from_data = lambda *args: []
            header_from_data = lambda *args: None

        floor_nodes = basement.xpath('Floor')
        header_nodes = basement.xpath('Components/FloorHeader')
        wall_nodes = basement.xpath('Wall')

        floors = floor_from_data(floor_nodes[0] if floor_nodes else None)
        walls = wall_from_data(wall_nodes[0], floors[0].perimeter.metres) if wall_nodes else []
        header = header_from_data(header_nodes[0]) if header_nodes else None

        try:
            configuration_type = basement.get('Configuration/@type', str)
            label = basement.get_text('Label')
        except ElementGetValueError as exc:
            raise InvalidEmbeddedDataTypeError(Basement, 'Missing/invalid foundation attributes') from exc

        if not configuration_type:
            raise InvalidEmbeddedDataTypeError(Basement, 'Empty configuration type')

        return Basement(
            foundation_type=foundation_type,
            label=label,
            configuration_type=configuration_type,
            walls=walls,
            floors=floors,
            header=header,
        )
Beispiel #6
0
 def _get_heating_type(cls, node: element.Element) -> HeatingType:
     candidates = [candidate.tag for candidate in node.xpath('Type1/*')]
     heating_type: typing.Optional[HeatingType] = None
     for candidate in candidates:
         if candidate in cls._HEATING_TYPE_NODE_NAMES:
             heating_type = cls._HEATING_TYPE_NODE_NAMES[candidate]
             break
     if heating_type is None:
         raise InvalidEmbeddedDataTypeError(
             Heating,
             f'Could not identify HeatingType, candidate node names = {[candidates]}'
         )
     return heating_type
Beispiel #7
0
    def _from_data(cls, water_heating: element.Element) -> 'WaterHeating':
        drain_water_efficiency: typing.Optional[float] = None
        if water_heating.get('@hasDrainWaterHeatRecovery', str) == 'true':
            drain_water_efficiency = water_heating.get(
                'DrainWaterHeatRecovery/@effectivenessAt9.5', float)

        try:
            energy_type = water_heating.get_text('EnergySource/English')
            tank_type = water_heating.get_text('TankType/English')

            water_heater_type = cls._TYPE_MAP[(energy_type.lower(),
                                               tank_type.lower())]
            volume = water_heating.get('TankVolume/@value', float)
        except ElementGetValueError as exc:
            raise InvalidEmbeddedDataTypeError(
                WaterHeating, 'Missing/invalid attribue or text') from exc
        except KeyError as exc:
            raise InvalidEmbeddedDataTypeError(
                WaterHeating,
                'Invlaid energy and tank type combination') from exc

        efficiency_ef_node = water_heating.xpath('EnergyFactor/@value')
        efficiency_percent_node = water_heating.xpath(
            'EnergyFactor/@thermalEfficiency')

        if not efficiency_ef_node and not efficiency_percent_node:
            raise InvalidEmbeddedDataTypeError(WaterHeating,
                                               'No efficiency values')

        return WaterHeating(
            water_heater_type=water_heater_type,
            tank_volume=volume,
            efficiency_ef=float(efficiency_ef_node[0])
            if efficiency_ef_node else None,
            efficiency_percentage=float(efficiency_percent_node[0])
            if efficiency_percent_node else None,
            drain_water_heat_recovery_efficiency_percentage=
            drain_water_efficiency,
        )
Beispiel #8
0
    def from_data(cls, wall: element.Element,
                  wall_codes: typing.Dict[str, code.WallCode]) -> 'Wall':

        code_id = wall.xpath('Construction/Type/@idref')
        wall_code = wall_codes[code_id[0]] if code_id else None

        try:
            return Wall(
                label=wall.get_text('Label'),
                wall_code=wall_code,
                nominal_insulation=insulation.Insulation(
                    wall.get('Construction/Type/@nominalInsulation', float)),
                effective_insulation=insulation.Insulation(
                    wall.get('Construction/Type/@rValue', float)),
                perimeter=distance.Distance(
                    wall.get('Measurements/@perimeter', float)),
                height=distance.Distance(
                    wall.get('Measurements/@height', float)),
            )
        except (ElementGetValueError) as exc:
            raise InvalidEmbeddedDataTypeError(Wall) from exc
Beispiel #9
0
    def from_crawlspace(cls, wall: element.Element, wall_perimeter: float) -> typing.List['BasementWall']:
        wall_sections = wall.xpath('Construction/Type/Composite/Section')

        try:
            wall_height = wall.get('Measurements/@height', float)
        except ElementGetValueError as exc:
            raise InvalidEmbeddedDataTypeError(BasementWall, 'Missing/invalid wall height') from exc

        percentages = [wall.attrib.get('percentage') for wall in wall_sections]
        accounted_for = sum(float(percentage) for percentage in percentages if percentage is not None)

        return [
            BasementWall._from_data(
                wall_section,
                wall_perimeter,
                wall_height,
                WallType.NOT_APPLICABLE,
                100-accounted_for
            )
            for wall_section in wall_sections
        ]
Beispiel #10
0
    def from_data(cls, window: element.Element,
                  window_codes: typing.Dict[str, code.WindowCode]) -> 'Window':

        code_id = window.xpath('Construction/Type/@idref')
        window_code = window_codes[code_id[0]] if code_id else None

        try:
            return Window(
                label=window.get_text('Label'),
                window_code=window_code,
                window_insulation=insulation.Insulation(
                    window.get('Construction/Type/@rValue', float)),
                width=distance.Distance(
                    window.get('Measurements/@width', float) /
                    _MILLIMETRES_TO_METRES),
                height=distance.Distance(
                    window.get('Measurements/@height', float) /
                    _MILLIMETRES_TO_METRES),
            )
        except (ElementGetValueError) as exc:
            raise InvalidEmbeddedDataTypeError(Window) from exc
Beispiel #11
0
def _extract_nodes(node: element.Element, path: str) -> typing.List[element.Element]:
    return node.xpath(path)
Beispiel #12
0
def test_xpath_returns_elements(fragment_node: element.Element) -> None:
    output = fragment_node.xpath('Bar')
    assert len(output) == 2
    assert all([isinstance(bar_node, element.Element) for bar_node in output])
    assert output[0].attrib['id'] == '1'
Beispiel #13
0
def snip_energy_upgrade_order(
        energy_upgrades: element.Element) -> EnergyUpgradesSnippet:
    upgrades = energy_upgrades.xpath('EnergyUpgrades/Settings/*')

    return EnergyUpgradesSnippet(
        upgrades=[upgrade.to_string() for upgrade in upgrades], )