mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
start mapping json
This commit is contained in:
parent
9e7d8c004f
commit
ff67297646
7 changed files with 137258 additions and 231 deletions
|
|
@ -1,14 +1,51 @@
|
||||||
from backend.magic_plan.models import MagicPlanDetail, MagicPlanSummary
|
import requests
|
||||||
|
|
||||||
|
from backend.magic_plan.models import (
|
||||||
|
MagicPlanPlan,
|
||||||
|
MagicPlanSummary,
|
||||||
|
MagicPlanXMLDetail,
|
||||||
|
MagicPlanXMLSummary,
|
||||||
|
)
|
||||||
|
from backend.magic_plan.xml_parser import parse_magicplan_xml
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_xml_summary(data: dict[str, object]) -> MagicPlanXMLSummary:
|
||||||
|
return MagicPlanXMLSummary(
|
||||||
|
id=str(data.get("id", "")),
|
||||||
|
project_id=str(data.get("project_id", "")),
|
||||||
|
name=str(data.get("name", "")),
|
||||||
|
address=str(data.get("address", "")),
|
||||||
|
creation_date=str(data.get("creation_date", "")),
|
||||||
|
update_date=str(data.get("update_date", "")),
|
||||||
|
workgroup_id=str(data.get("workgroup_id", "")),
|
||||||
|
team_id=str(data.get("team_id", "")),
|
||||||
|
created_by=str(data.get("created_by", "")),
|
||||||
|
thumbnail_url=str(data.get("thumbnail_url", "")),
|
||||||
|
public_url=str(data.get("public_url", "")),
|
||||||
|
cloud_url=str(data.get("cloud_url", "")),
|
||||||
|
url_3d=str(data.get("3d_url", "")),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MagicPlanClient:
|
class MagicPlanClient:
|
||||||
BASE_URL = "https://cloud.magicplan.app/api/v2"
|
BASE_URL = "https://cloud.magicplan.app/api/v2"
|
||||||
|
|
||||||
def __init__(self, _api_key: str) -> None:
|
def __init__(self, api_key: str) -> None:
|
||||||
raise NotImplementedError
|
self._session = requests.Session()
|
||||||
|
self._session.headers.update({"Authorization": f"Bearer {api_key}"})
|
||||||
|
|
||||||
def get_plans(self, _project_id: str) -> list[MagicPlanSummary]:
|
def get_plans(self, _project_id: str) -> list[MagicPlanSummary]:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def get_plan_xml(self, _plan_id: str) -> MagicPlanDetail:
|
def get_plan_xml(self, plan_id: str) -> MagicPlanXMLDetail:
|
||||||
|
resp = self._session.get(f"{self.BASE_URL}/plans/get/{plan_id}")
|
||||||
|
resp.raise_for_status()
|
||||||
|
data: dict[str, object] = resp.json()["data"]
|
||||||
|
plan_data = data["plan"] # type: ignore[index]
|
||||||
|
detail_data = data["plan_detail"] # type: ignore[index]
|
||||||
|
summary = _parse_xml_summary(plan_data) # type: ignore[arg-type]
|
||||||
|
plan_xml = parse_magicplan_xml(detail_data["magicplan_format_xml"]) # type: ignore[index]
|
||||||
|
return MagicPlanXMLDetail(summary=summary, plan_xml=plan_xml)
|
||||||
|
|
||||||
|
def get_plan(self, _plan_id: str) -> MagicPlanPlan:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
|
||||||
136742
backend/magic_plan/magicplan_api_plan_response_example.json
Normal file
136742
backend/magic_plan/magicplan_api_plan_response_example.json
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1,18 +1,40 @@
|
||||||
|
import re
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
|
|
||||||
|
def _camel_to_snake(name: str) -> str:
|
||||||
|
return re.sub(r"(?<!^)(?=[A-Z])", "_", name).lower()
|
||||||
|
|
||||||
|
|
||||||
|
def parse_displayable_fields(fields: list[dict[str, Any]]) -> dict[str, str]:
|
||||||
|
result: dict[str, str] = {}
|
||||||
|
for f in fields:
|
||||||
|
if f.get("type_as_string") == "sectionTitle":
|
||||||
|
continue
|
||||||
|
v: dict[str, Any] = f.get("value") or {}
|
||||||
|
if not v.get("has_value"):
|
||||||
|
continue
|
||||||
|
result[_camel_to_snake(str(f["id"]))] = str(v["value"])
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# XML dataclasses (sourced from MagicPlan Exchange XML format)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanRoomPoint:
|
class MagicPlanXMLRoomPoint:
|
||||||
snapped_x: float
|
snapped_x: float
|
||||||
snapped_y: float
|
snapped_y: float
|
||||||
height: float
|
height: float
|
||||||
uid: str
|
uid: str
|
||||||
values: dict[str, str] # e.g. loadBearingWall, addElevationToReport
|
values: dict[str, str]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanWallPoint:
|
class MagicPlanXMLWallPoint:
|
||||||
"""Point in <exploded><wall> — absolute coords, no uid or values."""
|
"""Point in <exploded><wall> — absolute coords, no uid or values."""
|
||||||
|
|
||||||
x: float
|
x: float
|
||||||
|
|
@ -21,21 +43,21 @@ class MagicPlanWallPoint:
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanDoor:
|
class MagicPlanXMLDoor:
|
||||||
"""Door in <floorRoom> context — wall-relative position."""
|
"""Door in <floorRoom> context — wall-relative position."""
|
||||||
|
|
||||||
wall_point_index: int
|
wall_point_index: int
|
||||||
type: str
|
type: str
|
||||||
u: float
|
u: float
|
||||||
width: float # m
|
width: float
|
||||||
depth: float # m
|
depth: float
|
||||||
height: float # m
|
height: float
|
||||||
orientation: int
|
orientation: int
|
||||||
snapped_type: str
|
snapped_type: str
|
||||||
snapped_position: float
|
snapped_position: float
|
||||||
snapped_width: float # m
|
snapped_width: float
|
||||||
snapped_depth: float # m
|
snapped_depth: float
|
||||||
snapped_height: float # m
|
snapped_height: float
|
||||||
snapped_orientation: int
|
snapped_orientation: int
|
||||||
inset_x: float
|
inset_x: float
|
||||||
inset_y: float
|
inset_y: float
|
||||||
|
|
@ -45,21 +67,21 @@ class MagicPlanDoor:
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanWindow:
|
class MagicPlanXMLWindow:
|
||||||
"""Window in <floorRoom> context — wall-relative position."""
|
"""Window in <floorRoom> context — wall-relative position."""
|
||||||
|
|
||||||
wall_point_index: int
|
wall_point_index: int
|
||||||
type: str
|
type: str
|
||||||
u: float
|
u: float
|
||||||
width: float # m
|
width: float
|
||||||
depth: float # m
|
depth: float
|
||||||
height: float # m
|
height: float
|
||||||
orientation: int
|
orientation: int
|
||||||
snapped_type: str
|
snapped_type: str
|
||||||
snapped_position: float
|
snapped_position: float
|
||||||
snapped_width: float # m
|
snapped_width: float
|
||||||
snapped_depth: float # m
|
snapped_depth: float
|
||||||
snapped_height: float # m
|
snapped_height: float
|
||||||
snapped_orientation: int
|
snapped_orientation: int
|
||||||
inset_x: float
|
inset_x: float
|
||||||
inset_y: float
|
inset_y: float
|
||||||
|
|
@ -68,7 +90,7 @@ class MagicPlanWindow:
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanExplodedOpening:
|
class MagicPlanXMLExplodedOpening:
|
||||||
"""Door or window in <exploded> context — absolute coords, no snapped* fields."""
|
"""Door or window in <exploded> context — absolute coords, no snapped* fields."""
|
||||||
|
|
||||||
type: str
|
type: str
|
||||||
|
|
@ -76,9 +98,9 @@ class MagicPlanExplodedOpening:
|
||||||
y1: float
|
y1: float
|
||||||
x2: float
|
x2: float
|
||||||
y2: float
|
y2: float
|
||||||
width: float # m
|
width: float
|
||||||
depth: float # m
|
depth: float
|
||||||
height: float # m
|
height: float
|
||||||
inset_x: float
|
inset_x: float
|
||||||
inset_y: float
|
inset_y: float
|
||||||
orientation: int
|
orientation: int
|
||||||
|
|
@ -86,19 +108,19 @@ class MagicPlanExplodedOpening:
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanFurniture:
|
class MagicPlanXMLFurniture:
|
||||||
type: str
|
type: str
|
||||||
x: float
|
x: float
|
||||||
y: float
|
y: float
|
||||||
snapped_x: float
|
snapped_x: float
|
||||||
snapped_y: float
|
snapped_y: float
|
||||||
angle: float
|
angle: float
|
||||||
width: float # m
|
width: float
|
||||||
depth: float # m
|
depth: float
|
||||||
height: float # m
|
height: float
|
||||||
snapped_width: float # m
|
snapped_width: float
|
||||||
snapped_depth: float # m
|
snapped_depth: float
|
||||||
snapped_height: float # m
|
snapped_height: float
|
||||||
size_lock_0: str
|
size_lock_0: str
|
||||||
size_lock_1: str
|
size_lock_1: str
|
||||||
size_lock_2: str
|
size_lock_2: str
|
||||||
|
|
@ -106,7 +128,7 @@ class MagicPlanFurniture:
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanMainDimension:
|
class MagicPlanXMLMainDimension:
|
||||||
from_point: int
|
from_point: int
|
||||||
to_point: int
|
to_point: int
|
||||||
dir_x: float
|
dir_x: float
|
||||||
|
|
@ -117,30 +139,30 @@ class MagicPlanMainDimension:
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanExplodedWall:
|
class MagicPlanXMLExplodedWall:
|
||||||
wall_type: str # "exterior" | "interior"
|
wall_type: str
|
||||||
points: list[MagicPlanWallPoint]
|
points: list[MagicPlanXMLWallPoint]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanExploded:
|
class MagicPlanXMLExploded:
|
||||||
walls: list[MagicPlanExplodedWall]
|
walls: list[MagicPlanXMLExplodedWall]
|
||||||
doors: list[MagicPlanExplodedOpening]
|
doors: list[MagicPlanXMLExplodedOpening]
|
||||||
windows: list[MagicPlanExplodedOpening]
|
windows: list[MagicPlanXMLExplodedOpening]
|
||||||
furniture: list[MagicPlanFurniture]
|
furniture: list[MagicPlanXMLFurniture]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanSymbolInstance:
|
class MagicPlanXMLSymbolInstance:
|
||||||
id: str
|
id: str
|
||||||
uid: str
|
uid: str
|
||||||
parent_uid: str
|
parent_uid: str
|
||||||
symbol: str
|
symbol: str
|
||||||
values: dict[str, str] # ceilingHeight, width, height, depth, distanceUnit, etc.
|
values: dict[str, str]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanRoom:
|
class MagicPlanXMLRoom:
|
||||||
uid: str
|
uid: str
|
||||||
type: str
|
type: str
|
||||||
x: float
|
x: float
|
||||||
|
|
@ -149,35 +171,35 @@ class MagicPlanRoom:
|
||||||
was_modified: bool
|
was_modified: bool
|
||||||
linked_room_0: str
|
linked_room_0: str
|
||||||
linked_room_1: str
|
linked_room_1: str
|
||||||
area: float # m²
|
area: float
|
||||||
perimeter: float # m
|
perimeter: float
|
||||||
values: dict[str, str] # ceilingHeight, label, etc.
|
values: dict[str, str]
|
||||||
points: list[MagicPlanRoomPoint]
|
points: list[MagicPlanXMLRoomPoint]
|
||||||
doors: list[MagicPlanDoor]
|
doors: list[MagicPlanXMLDoor]
|
||||||
windows: list[MagicPlanWindow]
|
windows: list[MagicPlanXMLWindow]
|
||||||
furniture: list[MagicPlanFurniture]
|
furniture: list[MagicPlanXMLFurniture]
|
||||||
main_dimensions: list[MagicPlanMainDimension]
|
main_dimensions: list[MagicPlanXMLMainDimension]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanFloor:
|
class MagicPlanXMLFloor:
|
||||||
uid: str
|
uid: str
|
||||||
name: str
|
name: str
|
||||||
floor_type: str # "0"=ground, "1"=upper, "2"=basement
|
floor_type: str
|
||||||
rotation: float
|
rotation: float
|
||||||
compass_angle: float
|
compass_angle: float
|
||||||
area_without_walls: float # m²
|
area_without_walls: float
|
||||||
area_with_interior_walls_only: float # m²
|
area_with_interior_walls_only: float
|
||||||
area_with_walls: float # m²
|
area_with_walls: float
|
||||||
symbol_instance: MagicPlanSymbolInstance
|
symbol_instance: MagicPlanXMLSymbolInstance
|
||||||
rooms: list[MagicPlanRoom]
|
rooms: list[MagicPlanXMLRoom]
|
||||||
furniture: list[MagicPlanFurniture] # floor-level furniture (not inside any room)
|
furniture: list[MagicPlanXMLFurniture]
|
||||||
exploded: MagicPlanExploded
|
exploded: MagicPlanXMLExploded
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanSummary:
|
class MagicPlanXMLSummary:
|
||||||
"""Plan metadata returned by the list-plans API endpoint."""
|
"""Plan metadata returned by the list-plans API endpoint (old string-address format)."""
|
||||||
|
|
||||||
id: str
|
id: str
|
||||||
project_id: str
|
project_id: str
|
||||||
|
|
@ -195,25 +217,201 @@ class MagicPlanSummary:
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanDetail:
|
class MagicPlanXMLDetail:
|
||||||
"""Full plan response: summary metadata + parsed XML plan."""
|
"""Full plan response: summary metadata + parsed XML plan."""
|
||||||
|
|
||||||
summary: MagicPlanSummary
|
summary: MagicPlanXMLSummary
|
||||||
plan_xml: "MagicPlanPlan"
|
plan_xml: "MagicPlanXMLPlan"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MagicPlanPlan:
|
class MagicPlanXMLPlan:
|
||||||
id: str
|
id: str
|
||||||
uid: str
|
uid: str
|
||||||
name: str
|
name: str
|
||||||
type: str
|
type: str
|
||||||
interior_wall_width: float # m
|
interior_wall_width: float
|
||||||
exterior_wall_width: float # m
|
exterior_wall_width: float
|
||||||
schematic: bool
|
schematic: bool
|
||||||
has_land_survey_address: bool
|
has_land_survey_address: bool
|
||||||
last_patch_identifier: str
|
last_patch_identifier: str
|
||||||
last_roll_identifier: str
|
last_roll_identifier: str
|
||||||
values: dict[str, str] # date, statistics.*, distanceUnit, etc.
|
values: dict[str, str]
|
||||||
|
floors: list[MagicPlanXMLFloor]
|
||||||
|
interior_room_floors: list[MagicPlanXMLFloor]
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# JSON dataclasses (sourced from GET Plan API JSON response)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MagicPlanWall:
|
||||||
|
uid: str
|
||||||
|
symbol_id: str
|
||||||
|
length: float
|
||||||
|
fields: dict[str, str]
|
||||||
|
custom_fields: dict[str, str]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MagicPlanWallItem:
|
||||||
|
"""Door or window — distinguished by symbol_id."""
|
||||||
|
|
||||||
|
uid: str
|
||||||
|
symbol_id: str
|
||||||
|
symbol_name: str
|
||||||
|
width: float
|
||||||
|
depth: float
|
||||||
|
height: float
|
||||||
|
pos_x: float
|
||||||
|
pos_y: float
|
||||||
|
pos_z: float
|
||||||
|
rotation_z: float
|
||||||
|
fields: dict[str, str]
|
||||||
|
custom_fields: dict[str, str]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MagicPlanFurniture:
|
||||||
|
uid: str
|
||||||
|
symbol_id: str
|
||||||
|
symbol_name: str
|
||||||
|
width: float
|
||||||
|
depth: float
|
||||||
|
height: float
|
||||||
|
pos_x: float
|
||||||
|
pos_y: float
|
||||||
|
pos_z: float
|
||||||
|
rotation_z: float
|
||||||
|
fields: dict[str, str]
|
||||||
|
custom_fields: dict[str, str]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MagicPlanRoom:
|
||||||
|
uid: str
|
||||||
|
name: str
|
||||||
|
area: float
|
||||||
|
perimeter: float
|
||||||
|
height: float
|
||||||
|
width: float
|
||||||
|
volume: float
|
||||||
|
dimensions: str
|
||||||
|
door_count: int
|
||||||
|
window_count: int
|
||||||
|
walls_surface: float
|
||||||
|
walls_surface_without_openings: float
|
||||||
|
doors_surface: float
|
||||||
|
windows_surface: float
|
||||||
|
wall_items: list[MagicPlanWallItem]
|
||||||
|
furnitures: list[MagicPlanFurniture]
|
||||||
|
walls: list[MagicPlanWall]
|
||||||
|
fields: dict[str, str]
|
||||||
|
custom_fields: dict[str, str]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MagicPlanFloor:
|
||||||
|
uid: str
|
||||||
|
name: str
|
||||||
|
floor_type: str
|
||||||
|
area: float
|
||||||
|
perimeter: float
|
||||||
|
area_without_walls: float
|
||||||
|
area_with_interior_walls_only: float
|
||||||
|
area_with_walls: float
|
||||||
|
wall_count: int
|
||||||
|
wall_count_with_interior_walls: int
|
||||||
|
door_count: int
|
||||||
|
window_count: int
|
||||||
|
room_count: int
|
||||||
|
furniture_count: int
|
||||||
|
doors_surface: float
|
||||||
|
walls_surface: float
|
||||||
|
walls_surface_without_openings: float
|
||||||
|
windows_surface: float
|
||||||
|
volume: float
|
||||||
|
rooms: list[MagicPlanRoom]
|
||||||
|
furnitures: list[MagicPlanFurniture]
|
||||||
|
symbol_instances: list[MagicPlanFurniture]
|
||||||
|
fields: dict[str, str]
|
||||||
|
custom_fields: dict[str, str]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MagicPlanPlan:
|
||||||
|
"""GET /plans/{id} — merged data.plan + data.plan_detail.plan."""
|
||||||
|
|
||||||
|
id: str
|
||||||
|
project_id: str
|
||||||
|
uid: str
|
||||||
|
name: str
|
||||||
|
area: float
|
||||||
|
perimeter: float
|
||||||
|
area_without_walls: float
|
||||||
|
area_with_interior_walls_only: float
|
||||||
|
area_with_walls: float
|
||||||
|
wall_count: int
|
||||||
|
door_count: int
|
||||||
|
window_count: int
|
||||||
|
room_count: int
|
||||||
|
furniture_count: int
|
||||||
|
floor_count: int
|
||||||
|
doors_surface: float
|
||||||
|
walls_surface: float
|
||||||
|
walls_surface_without_openings: float
|
||||||
|
windows_surface: float
|
||||||
|
volume: float
|
||||||
|
living_area: float
|
||||||
|
below_grade_living_area: float
|
||||||
|
above_grade_living_area: float
|
||||||
|
address_street: Optional[str]
|
||||||
|
address_postal_code: Optional[str]
|
||||||
|
address_city: Optional[str]
|
||||||
|
address_country: Optional[str]
|
||||||
|
address_longitude: Optional[float]
|
||||||
|
address_latitude: Optional[float]
|
||||||
|
creation_date: str
|
||||||
|
update_date: str
|
||||||
|
workgroup_id: str
|
||||||
|
team_id: str
|
||||||
|
created_by_id: str
|
||||||
|
created_by_firstname: Optional[str]
|
||||||
|
created_by_lastname: Optional[str]
|
||||||
|
created_by_email: str
|
||||||
|
thumbnail_url: str
|
||||||
|
public_url: str
|
||||||
|
cloud_url: str
|
||||||
|
url_3d: str
|
||||||
floors: list[MagicPlanFloor]
|
floors: list[MagicPlanFloor]
|
||||||
interior_room_floors: list[MagicPlanFloor] # from <interiorRoomPoints>
|
fields: dict[str, str]
|
||||||
|
custom_fields: dict[str, str]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MagicPlanSummary:
|
||||||
|
"""GET /plans list — lightweight, flat address and creator fields."""
|
||||||
|
|
||||||
|
id: str
|
||||||
|
project_id: str
|
||||||
|
name: str
|
||||||
|
address_street: Optional[str]
|
||||||
|
address_postal_code: Optional[str]
|
||||||
|
address_city: Optional[str]
|
||||||
|
address_country: Optional[str]
|
||||||
|
address_longitude: Optional[float]
|
||||||
|
address_latitude: Optional[float]
|
||||||
|
creation_date: str
|
||||||
|
update_date: str
|
||||||
|
workgroup_id: str
|
||||||
|
team_id: str
|
||||||
|
created_by_id: str
|
||||||
|
created_by_firstname: Optional[str]
|
||||||
|
created_by_lastname: Optional[str]
|
||||||
|
created_by_email: str
|
||||||
|
thumbnail_url: str
|
||||||
|
public_url: str
|
||||||
|
cloud_url: str
|
||||||
|
url_3d: str
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import pytest
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from backend.magic_plan.magic_plan_client import MagicPlanClient
|
from backend.magic_plan.magic_plan_client import MagicPlanClient
|
||||||
from backend.magic_plan.models import MagicPlanDetail, MagicPlanPlan, MagicPlanSummary
|
from backend.magic_plan.models import MagicPlanXMLDetail, MagicPlanXMLPlan, MagicPlanXMLSummary
|
||||||
|
|
||||||
FIXTURES = Path(__file__).parent.parent
|
FIXTURES = Path(__file__).parent.parent
|
||||||
API_KEY = "test-api-key"
|
API_KEY = "test-api-key"
|
||||||
|
|
@ -107,12 +107,12 @@ class TestGetPlanXml:
|
||||||
def test_returns_magic_plan_detail(self, client: MagicPlanClient, mock_session: MagicMock) -> None:
|
def test_returns_magic_plan_detail(self, client: MagicPlanClient, mock_session: MagicMock) -> None:
|
||||||
mock_session.get.return_value.json.return_value = _get_plan_response(_load_xml())
|
mock_session.get.return_value.json.return_value = _get_plan_response(_load_xml())
|
||||||
result = client.get_plan_xml(PLAN_ID)
|
result = client.get_plan_xml(PLAN_ID)
|
||||||
assert isinstance(result, MagicPlanDetail)
|
assert isinstance(result, MagicPlanXMLDetail)
|
||||||
|
|
||||||
def test_detail_contains_summary(self, client: MagicPlanClient, mock_session: MagicMock) -> None:
|
def test_detail_contains_summary(self, client: MagicPlanClient, mock_session: MagicMock) -> None:
|
||||||
mock_session.get.return_value.json.return_value = _get_plan_response(_load_xml())
|
mock_session.get.return_value.json.return_value = _get_plan_response(_load_xml())
|
||||||
result = client.get_plan_xml(PLAN_ID)
|
result = client.get_plan_xml(PLAN_ID)
|
||||||
assert isinstance(result.summary, MagicPlanSummary)
|
assert isinstance(result.summary, MagicPlanXMLSummary)
|
||||||
|
|
||||||
def test_detail_summary_id(self, client: MagicPlanClient, mock_session: MagicMock) -> None:
|
def test_detail_summary_id(self, client: MagicPlanClient, mock_session: MagicMock) -> None:
|
||||||
mock_session.get.return_value.json.return_value = _get_plan_response(_load_xml())
|
mock_session.get.return_value.json.return_value = _get_plan_response(_load_xml())
|
||||||
|
|
@ -127,7 +127,7 @@ class TestGetPlanXml:
|
||||||
def test_detail_contains_parsed_plan(self, client: MagicPlanClient, mock_session: MagicMock) -> None:
|
def test_detail_contains_parsed_plan(self, client: MagicPlanClient, mock_session: MagicMock) -> None:
|
||||||
mock_session.get.return_value.json.return_value = _get_plan_response(_load_xml())
|
mock_session.get.return_value.json.return_value = _get_plan_response(_load_xml())
|
||||||
result = client.get_plan_xml(PLAN_ID)
|
result = client.get_plan_xml(PLAN_ID)
|
||||||
assert isinstance(result.plan_xml, MagicPlanPlan)
|
assert isinstance(result.plan_xml, MagicPlanXMLPlan)
|
||||||
|
|
||||||
def test_plan_xml_id_matches_xml(self, client: MagicPlanClient, mock_session: MagicMock) -> None:
|
def test_plan_xml_id_matches_xml(self, client: MagicPlanClient, mock_session: MagicMock) -> None:
|
||||||
mock_session.get.return_value.json.return_value = _get_plan_response(_load_xml())
|
mock_session.get.return_value.json.return_value = _get_plan_response(_load_xml())
|
||||||
|
|
@ -167,7 +167,7 @@ class TestGetPlans:
|
||||||
mock_session.get.return_value.json.return_value = _get_plans_response([PLAN_ID, "other-id"])
|
mock_session.get.return_value.json.return_value = _get_plans_response([PLAN_ID, "other-id"])
|
||||||
result = client.get_plans(PROJECT_ID)
|
result = client.get_plans(PROJECT_ID)
|
||||||
assert len(result) == 2
|
assert len(result) == 2
|
||||||
assert all(isinstance(s, MagicPlanSummary) for s in result)
|
assert all(isinstance(s, MagicPlanXMLSummary) for s in result)
|
||||||
|
|
||||||
def test_summary_id(self, client: MagicPlanClient, mock_session: MagicMock) -> None:
|
def test_summary_id(self, client: MagicPlanClient, mock_session: MagicMock) -> None:
|
||||||
mock_session.get.return_value.json.return_value = _get_plans_response([PLAN_ID])
|
mock_session.get.return_value.json.return_value = _get_plans_response([PLAN_ID])
|
||||||
|
|
|
||||||
50
backend/magic_plan/tests/test_models.py
Normal file
50
backend/magic_plan/tests/test_models.py
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from backend.magic_plan.models import parse_displayable_fields
|
||||||
|
|
||||||
|
|
||||||
|
SECTION_TITLE_FIELD = {
|
||||||
|
"id": "measures.section.title",
|
||||||
|
"type_as_string": "sectionTitle",
|
||||||
|
"value": {"has_value": False, "value": ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
CEILING_HEIGHT_FIELD = {
|
||||||
|
"id": "ceilingHeight",
|
||||||
|
"type_as_string": "distance",
|
||||||
|
"value": {"has_value": True, "value": "2.45"},
|
||||||
|
}
|
||||||
|
|
||||||
|
NO_VALUE_FIELD = {
|
||||||
|
"id": "label",
|
||||||
|
"type_as_string": "text",
|
||||||
|
"value": {"has_value": False, "value": ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestParseDisplayableFields:
|
||||||
|
|
||||||
|
def test_excludes_section_titles(self) -> None:
|
||||||
|
result = parse_displayable_fields([SECTION_TITLE_FIELD])
|
||||||
|
assert result == {}
|
||||||
|
|
||||||
|
def test_excludes_fields_without_value(self) -> None:
|
||||||
|
result = parse_displayable_fields([NO_VALUE_FIELD])
|
||||||
|
assert result == {}
|
||||||
|
|
||||||
|
def test_includes_field_with_value(self) -> None:
|
||||||
|
result = parse_displayable_fields([CEILING_HEIGHT_FIELD])
|
||||||
|
assert "ceiling_height" in result
|
||||||
|
assert result["ceiling_height"] == "2.45"
|
||||||
|
|
||||||
|
def test_snake_cases_camel_key(self) -> None:
|
||||||
|
result = parse_displayable_fields([CEILING_HEIGHT_FIELD])
|
||||||
|
assert "ceiling_height" in result
|
||||||
|
assert "ceilingHeight" not in result
|
||||||
|
|
||||||
|
def test_mixed_fields(self) -> None:
|
||||||
|
result = parse_displayable_fields([SECTION_TITLE_FIELD, CEILING_HEIGHT_FIELD, NO_VALUE_FIELD])
|
||||||
|
assert result == {"ceiling_height": "2.45"}
|
||||||
|
|
||||||
|
def test_empty_list(self) -> None:
|
||||||
|
assert parse_displayable_fields([]) == {}
|
||||||
|
|
@ -5,7 +5,7 @@ from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from backend.magic_plan.models import MagicPlanPlan
|
from backend.magic_plan.models import MagicPlanXMLPlan
|
||||||
from backend.magic_plan.xml_parser import parse_magicplan_xml
|
from backend.magic_plan.xml_parser import parse_magicplan_xml
|
||||||
|
|
||||||
FIXTURES = Path(__file__).parent.parent
|
FIXTURES = Path(__file__).parent.parent
|
||||||
|
|
@ -21,17 +21,17 @@ def _load(filename: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def plan1() -> MagicPlanPlan:
|
def plan1() -> MagicPlanXMLPlan:
|
||||||
return parse_magicplan_xml(_load("xml_example.xml"))
|
return parse_magicplan_xml(_load("xml_example.xml"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def plan2() -> MagicPlanPlan:
|
def plan2() -> MagicPlanXMLPlan:
|
||||||
return parse_magicplan_xml(_load("xml_example_2.xml"))
|
return parse_magicplan_xml(_load("xml_example_2.xml"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def plan3() -> MagicPlanPlan:
|
def plan3() -> MagicPlanXMLPlan:
|
||||||
return parse_magicplan_xml(_load("xml_example_3.xml"))
|
return parse_magicplan_xml(_load("xml_example_3.xml"))
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -41,55 +41,55 @@ def plan3() -> MagicPlanPlan:
|
||||||
|
|
||||||
class TestPlanAttributes:
|
class TestPlanAttributes:
|
||||||
|
|
||||||
def test_id(self, plan1: MagicPlanPlan) -> None:
|
def test_id(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.id == "b66bb427-33fe-4865-8d57-bad7d9d3f2e5"
|
assert plan1.id == "b66bb427-33fe-4865-8d57-bad7d9d3f2e5"
|
||||||
|
|
||||||
def test_uid(self, plan1: MagicPlanPlan) -> None:
|
def test_uid(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.uid == "69e5fafc.0890b3ff"
|
assert plan1.uid == "69e5fafc.0890b3ff"
|
||||||
|
|
||||||
def test_name(self, plan1: MagicPlanPlan) -> None:
|
def test_name(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.name == "275 Carr Hill Rd NE9 5ND"
|
assert plan1.name == "275 Carr Hill Rd NE9 5ND"
|
||||||
|
|
||||||
def test_type(self, plan1: MagicPlanPlan) -> None:
|
def test_type(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.type == "0"
|
assert plan1.type == "0"
|
||||||
|
|
||||||
def test_interior_wall_width(self, plan1: MagicPlanPlan) -> None:
|
def test_interior_wall_width(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.interior_wall_width, 0.12)
|
assert math.isclose(plan1.interior_wall_width, 0.12)
|
||||||
|
|
||||||
def test_exterior_wall_width(self, plan1: MagicPlanPlan) -> None:
|
def test_exterior_wall_width(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.exterior_wall_width, 0.25)
|
assert math.isclose(plan1.exterior_wall_width, 0.25)
|
||||||
|
|
||||||
def test_schematic_false(self, plan1: MagicPlanPlan) -> None:
|
def test_schematic_false(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.schematic is False
|
assert plan1.schematic is False
|
||||||
|
|
||||||
def test_has_land_survey_address_false(self, plan1: MagicPlanPlan) -> None:
|
def test_has_land_survey_address_false(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.has_land_survey_address is False
|
assert plan1.has_land_survey_address is False
|
||||||
|
|
||||||
def test_last_patch_identifier(self, plan1: MagicPlanPlan) -> None:
|
def test_last_patch_identifier(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.last_patch_identifier == "0"
|
assert plan1.last_patch_identifier == "0"
|
||||||
|
|
||||||
def test_last_roll_identifier(self, plan1: MagicPlanPlan) -> None:
|
def test_last_roll_identifier(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.last_roll_identifier == "0"
|
assert plan1.last_roll_identifier == "0"
|
||||||
|
|
||||||
|
|
||||||
class TestPlanValues:
|
class TestPlanValues:
|
||||||
|
|
||||||
def test_date(self, plan1: MagicPlanPlan) -> None:
|
def test_date(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.values["date"] == "2026-04-20"
|
assert plan1.values["date"] == "2026-04-20"
|
||||||
|
|
||||||
def test_statistics_area_of_height(self, plan1: MagicPlanPlan) -> None:
|
def test_statistics_area_of_height(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.values["statistics.areaOfHeight"] == "2.134"
|
assert plan1.values["statistics.areaOfHeight"] == "2.134"
|
||||||
|
|
||||||
def test_statistics_basement_account(self, plan1: MagicPlanPlan) -> None:
|
def test_statistics_basement_account(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.values["statistics.basement.account"] == "100"
|
assert plan1.values["statistics.basement.account"] == "100"
|
||||||
|
|
||||||
def test_statistics_exterior_walls(self, plan1: MagicPlanPlan) -> None:
|
def test_statistics_exterior_walls(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.values["statistics.exteriorWalls"] == "0"
|
assert plan1.values["statistics.exteriorWalls"] == "0"
|
||||||
|
|
||||||
def test_statistics_interior_walls(self, plan1: MagicPlanPlan) -> None:
|
def test_statistics_interior_walls(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.values["statistics.interiorWalls"] == "0"
|
assert plan1.values["statistics.interiorWalls"] == "0"
|
||||||
|
|
||||||
def test_plan2_date(self, plan2: MagicPlanPlan) -> None:
|
def test_plan2_date(self, plan2: MagicPlanXMLPlan) -> None:
|
||||||
assert plan2.values["date"] == "2026-04-16"
|
assert plan2.values["date"] == "2026-04-16"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -99,43 +99,43 @@ class TestPlanValues:
|
||||||
|
|
||||||
class TestFloors:
|
class TestFloors:
|
||||||
|
|
||||||
def test_floor_count_plan1(self, plan1: MagicPlanPlan) -> None:
|
def test_floor_count_plan1(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan1.floors) == 2
|
assert len(plan1.floors) == 2
|
||||||
|
|
||||||
def test_floor_count_plan2(self, plan2: MagicPlanPlan) -> None:
|
def test_floor_count_plan2(self, plan2: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan2.floors) == 1
|
assert len(plan2.floors) == 1
|
||||||
|
|
||||||
def test_floor_count_plan3(self, plan3: MagicPlanPlan) -> None:
|
def test_floor_count_plan3(self, plan3: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan3.floors) == 1
|
assert len(plan3.floors) == 1
|
||||||
|
|
||||||
def test_ground_floor_name(self, plan1: MagicPlanPlan) -> None:
|
def test_ground_floor_name(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].name == "Ground Floor"
|
assert plan1.floors[0].name == "Ground Floor"
|
||||||
|
|
||||||
def test_first_floor_name(self, plan1: MagicPlanPlan) -> None:
|
def test_first_floor_name(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[1].name == "1st Floor"
|
assert plan1.floors[1].name == "1st Floor"
|
||||||
|
|
||||||
def test_ground_floor_type(self, plan1: MagicPlanPlan) -> None:
|
def test_ground_floor_type(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].floor_type == "0"
|
assert plan1.floors[0].floor_type == "0"
|
||||||
|
|
||||||
def test_upper_floor_type(self, plan1: MagicPlanPlan) -> None:
|
def test_upper_floor_type(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[1].floor_type == "1"
|
assert plan1.floors[1].floor_type == "1"
|
||||||
|
|
||||||
def test_floor_uid(self, plan1: MagicPlanPlan) -> None:
|
def test_floor_uid(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].uid == "69e5fb20.4feef7ff"
|
assert plan1.floors[0].uid == "69e5fb20.4feef7ff"
|
||||||
|
|
||||||
def test_ground_floor_area_without_walls(self, plan1: MagicPlanPlan) -> None:
|
def test_ground_floor_area_without_walls(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].area_without_walls, 40.20736)
|
assert math.isclose(plan1.floors[0].area_without_walls, 40.20736)
|
||||||
|
|
||||||
def test_ground_floor_area_with_walls(self, plan1: MagicPlanPlan) -> None:
|
def test_ground_floor_area_with_walls(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].area_with_walls, 48.40593)
|
assert math.isclose(plan1.floors[0].area_with_walls, 48.40593)
|
||||||
|
|
||||||
def test_ground_floor_area_with_interior_walls_only(self, plan1: MagicPlanPlan) -> None:
|
def test_ground_floor_area_with_interior_walls_only(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].area_with_interior_walls_only, 40.67878)
|
assert math.isclose(plan1.floors[0].area_with_interior_walls_only, 40.67878)
|
||||||
|
|
||||||
def test_floor_rotation(self, plan1: MagicPlanPlan) -> None:
|
def test_floor_rotation(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rotation, 0.0, abs_tol=1e-9)
|
assert math.isclose(plan1.floors[0].rotation, 0.0, abs_tol=1e-9)
|
||||||
|
|
||||||
def test_floor_compass_angle(self, plan1: MagicPlanPlan) -> None:
|
def test_floor_compass_angle(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].compass_angle, -1.0)
|
assert math.isclose(plan1.floors[0].compass_angle, -1.0)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -145,19 +145,19 @@ class TestFloors:
|
||||||
|
|
||||||
class TestSymbolInstance:
|
class TestSymbolInstance:
|
||||||
|
|
||||||
def test_symbol_instance_id(self, plan1: MagicPlanPlan) -> None:
|
def test_symbol_instance_id(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].symbol_instance.id == "floor"
|
assert plan1.floors[0].symbol_instance.id == "floor"
|
||||||
|
|
||||||
def test_symbol_instance_uid(self, plan1: MagicPlanPlan) -> None:
|
def test_symbol_instance_uid(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].symbol_instance.uid == "69e5fb20.4feef7ff"
|
assert plan1.floors[0].symbol_instance.uid == "69e5fb20.4feef7ff"
|
||||||
|
|
||||||
def test_symbol_instance_symbol(self, plan1: MagicPlanPlan) -> None:
|
def test_symbol_instance_symbol(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].symbol_instance.symbol == "floor"
|
assert plan1.floors[0].symbol_instance.symbol == "floor"
|
||||||
|
|
||||||
def test_symbol_instance_parent_uid(self, plan1: MagicPlanPlan) -> None:
|
def test_symbol_instance_parent_uid(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].symbol_instance.parent_uid == ""
|
assert plan1.floors[0].symbol_instance.parent_uid == ""
|
||||||
|
|
||||||
def test_symbol_instance_ceiling_height_value(self, plan1: MagicPlanPlan) -> None:
|
def test_symbol_instance_ceiling_height_value(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].symbol_instance.values["ceilingHeight"] == "2.323164"
|
assert plan1.floors[0].symbol_instance.values["ceilingHeight"] == "2.323164"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -167,59 +167,59 @@ class TestSymbolInstance:
|
||||||
|
|
||||||
class TestRooms:
|
class TestRooms:
|
||||||
|
|
||||||
def test_ground_floor_room_count(self, plan1: MagicPlanPlan) -> None:
|
def test_ground_floor_room_count(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan1.floors[0].rooms) == 2
|
assert len(plan1.floors[0].rooms) == 2
|
||||||
|
|
||||||
def test_first_floor_room_count(self, plan1: MagicPlanPlan) -> None:
|
def test_first_floor_room_count(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan1.floors[1].rooms) == 4
|
assert len(plan1.floors[1].rooms) == 4
|
||||||
|
|
||||||
def test_plan3_room_count(self, plan3: MagicPlanPlan) -> None:
|
def test_plan3_room_count(self, plan3: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan3.floors[0].rooms) == 9
|
assert len(plan3.floors[0].rooms) == 9
|
||||||
|
|
||||||
def test_room_type(self, plan1: MagicPlanPlan) -> None:
|
def test_room_type(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].type == "Kitchen"
|
assert plan1.floors[0].rooms[0].type == "Kitchen"
|
||||||
|
|
||||||
def test_room_uid(self, plan1: MagicPlanPlan) -> None:
|
def test_room_uid(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].uid == "69e5fbc8.71027bff"
|
assert plan1.floors[0].rooms[0].uid == "69e5fbc8.71027bff"
|
||||||
|
|
||||||
def test_room_area(self, plan1: MagicPlanPlan) -> None:
|
def test_room_area(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].area, 10.78332)
|
assert math.isclose(plan1.floors[0].rooms[0].area, 10.78332)
|
||||||
|
|
||||||
def test_room_perimeter(self, plan1: MagicPlanPlan) -> None:
|
def test_room_perimeter(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].perimeter, 13.32812)
|
assert math.isclose(plan1.floors[0].rooms[0].perimeter, 13.32812)
|
||||||
|
|
||||||
def test_room_x(self, plan1: MagicPlanPlan) -> None:
|
def test_room_x(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].x, 3.80616)
|
assert math.isclose(plan1.floors[0].rooms[0].x, 3.80616)
|
||||||
|
|
||||||
def test_room_y(self, plan1: MagicPlanPlan) -> None:
|
def test_room_y(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].y, 0.23162)
|
assert math.isclose(plan1.floors[0].rooms[0].y, 0.23162)
|
||||||
|
|
||||||
def test_room_rotation(self, plan1: MagicPlanPlan) -> None:
|
def test_room_rotation(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].rotation, 0.0, abs_tol=1e-9)
|
assert math.isclose(plan1.floors[0].rooms[0].rotation, 0.0, abs_tol=1e-9)
|
||||||
|
|
||||||
def test_room_was_modified_false(self, plan1: MagicPlanPlan) -> None:
|
def test_room_was_modified_false(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].was_modified is False
|
assert plan1.floors[0].rooms[0].was_modified is False
|
||||||
|
|
||||||
def test_room_was_modified_true(self, plan1: MagicPlanPlan) -> None:
|
def test_room_was_modified_true(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
closet = plan1.floors[1].rooms[1]
|
closet = plan1.floors[1].rooms[1]
|
||||||
assert closet.type == "Closet"
|
assert closet.type == "Closet"
|
||||||
assert closet.was_modified is True
|
assert closet.was_modified is True
|
||||||
|
|
||||||
def test_room_linked_room_0(self, plan1: MagicPlanPlan) -> None:
|
def test_room_linked_room_0(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].linked_room_0 == "-1"
|
assert plan1.floors[0].rooms[0].linked_room_0 == "-1"
|
||||||
|
|
||||||
def test_room_linked_room_1(self, plan1: MagicPlanPlan) -> None:
|
def test_room_linked_room_1(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].linked_room_1 == "-1"
|
assert plan1.floors[0].rooms[0].linked_room_1 == "-1"
|
||||||
|
|
||||||
def test_room_ceiling_height_value(self, plan1: MagicPlanPlan) -> None:
|
def test_room_ceiling_height_value(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].values["ceilingHeight"] == "2.323164"
|
assert plan1.floors[0].rooms[0].values["ceilingHeight"] == "2.323164"
|
||||||
|
|
||||||
def test_room_label_value(self, plan2: MagicPlanPlan) -> None:
|
def test_room_label_value(self, plan2: MagicPlanXMLPlan) -> None:
|
||||||
dining = plan2.floors[0].rooms[1]
|
dining = plan2.floors[0].rooms[1]
|
||||||
assert dining.type == "Dining Room"
|
assert dining.type == "Dining Room"
|
||||||
assert dining.values["label"] == "Room"
|
assert dining.values["label"] == "Room"
|
||||||
|
|
||||||
def test_room_no_label_when_absent(self, plan1: MagicPlanPlan) -> None:
|
def test_room_no_label_when_absent(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert "label" not in plan1.floors[0].rooms[0].values
|
assert "label" not in plan1.floors[0].rooms[0].values
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -229,25 +229,25 @@ class TestRooms:
|
||||||
|
|
||||||
class TestRoomPoints:
|
class TestRoomPoints:
|
||||||
|
|
||||||
def test_kitchen_point_count(self, plan1: MagicPlanPlan) -> None:
|
def test_kitchen_point_count(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan1.floors[0].rooms[0].points) == 4
|
assert len(plan1.floors[0].rooms[0].points) == 4
|
||||||
|
|
||||||
def test_living_room_point_count(self, plan1: MagicPlanPlan) -> None:
|
def test_living_room_point_count(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan1.floors[0].rooms[1].points) == 8
|
assert len(plan1.floors[0].rooms[1].points) == 8
|
||||||
|
|
||||||
def test_point_snapped_x(self, plan1: MagicPlanPlan) -> None:
|
def test_point_snapped_x(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].points[0].snapped_x, -1.44357)
|
assert math.isclose(plan1.floors[0].rooms[0].points[0].snapped_x, -1.44357)
|
||||||
|
|
||||||
def test_point_snapped_y(self, plan1: MagicPlanPlan) -> None:
|
def test_point_snapped_y(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].points[0].snapped_y, -2.00846)
|
assert math.isclose(plan1.floors[0].rooms[0].points[0].snapped_y, -2.00846)
|
||||||
|
|
||||||
def test_point_height(self, plan1: MagicPlanPlan) -> None:
|
def test_point_height(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].points[0].height, 2.323164)
|
assert math.isclose(plan1.floors[0].rooms[0].points[0].height, 2.323164)
|
||||||
|
|
||||||
def test_point_uid(self, plan1: MagicPlanPlan) -> None:
|
def test_point_uid(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].points[0].uid == "69e5fbc8.710363ff"
|
assert plan1.floors[0].rooms[0].points[0].uid == "69e5fbc8.710363ff"
|
||||||
|
|
||||||
def test_point_values_empty_when_absent(self, plan1: MagicPlanPlan) -> None:
|
def test_point_values_empty_when_absent(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].points[0].values == {}
|
assert plan1.floors[0].rooms[0].points[0].values == {}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -257,40 +257,40 @@ class TestRoomPoints:
|
||||||
|
|
||||||
class TestDoors:
|
class TestDoors:
|
||||||
|
|
||||||
def test_kitchen_door_count(self, plan1: MagicPlanPlan) -> None:
|
def test_kitchen_door_count(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan1.floors[0].rooms[0].doors) == 5
|
assert len(plan1.floors[0].rooms[0].doors) == 5
|
||||||
|
|
||||||
def test_corridor_door_count(self, plan3: MagicPlanPlan) -> None:
|
def test_corridor_door_count(self, plan3: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan3.floors[0].rooms[0].doors) == 9
|
assert len(plan3.floors[0].rooms[0].doors) == 9
|
||||||
|
|
||||||
def test_door_wall_point_index(self, plan1: MagicPlanPlan) -> None:
|
def test_door_wall_point_index(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].doors[0].wall_point_index == 3
|
assert plan1.floors[0].rooms[0].doors[0].wall_point_index == 3
|
||||||
|
|
||||||
def test_door_type(self, plan1: MagicPlanPlan) -> None:
|
def test_door_type(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].doors[0].type == "4"
|
assert plan1.floors[0].rooms[0].doors[0].type == "4"
|
||||||
|
|
||||||
def test_door_u(self, plan1: MagicPlanPlan) -> None:
|
def test_door_u(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].doors[0].u, 0.47585)
|
assert math.isclose(plan1.floors[0].rooms[0].doors[0].u, 0.47585)
|
||||||
|
|
||||||
def test_door_snapped_width(self, plan1: MagicPlanPlan) -> None:
|
def test_door_snapped_width(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].doors[0].snapped_width, 1.82394)
|
assert math.isclose(plan1.floors[0].rooms[0].doors[0].snapped_width, 1.82394)
|
||||||
|
|
||||||
def test_door_snapped_height(self, plan1: MagicPlanPlan) -> None:
|
def test_door_snapped_height(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].doors[0].snapped_height, 2.08411)
|
assert math.isclose(plan1.floors[0].rooms[0].doors[0].snapped_height, 2.08411)
|
||||||
|
|
||||||
def test_door_snapped_orientation(self, plan1: MagicPlanPlan) -> None:
|
def test_door_snapped_orientation(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].doors[0].snapped_orientation == 3
|
assert plan1.floors[0].rooms[0].doors[0].snapped_orientation == 3
|
||||||
|
|
||||||
def test_door_twin_wall_item_uid_present(self, plan1: MagicPlanPlan) -> None:
|
def test_door_twin_wall_item_uid_present(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].doors[0].twin_wall_item_uid == "69e5fbc8.74614fff"
|
assert plan1.floors[0].rooms[0].doors[0].twin_wall_item_uid == "69e5fbc8.74614fff"
|
||||||
|
|
||||||
def test_door_twin_wall_item_uid_absent(self, plan2: MagicPlanPlan) -> None:
|
def test_door_twin_wall_item_uid_absent(self, plan2: MagicPlanXMLPlan) -> None:
|
||||||
assert plan2.floors[0].rooms[0].doors[0].twin_wall_item_uid is None
|
assert plan2.floors[0].rooms[0].doors[0].twin_wall_item_uid is None
|
||||||
|
|
||||||
def test_door_symbol_instance(self, plan1: MagicPlanPlan) -> None:
|
def test_door_symbol_instance(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].doors[0].symbol_instance == "W-0-0"
|
assert plan1.floors[0].rooms[0].doors[0].symbol_instance == "W-0-0"
|
||||||
|
|
||||||
def test_door_inset_x(self, plan1: MagicPlanPlan) -> None:
|
def test_door_inset_x(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].doors[0].inset_x, 0.0, abs_tol=1e-9)
|
assert math.isclose(plan1.floors[0].rooms[0].doors[0].inset_x, 0.0, abs_tol=1e-9)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -300,30 +300,30 @@ class TestDoors:
|
||||||
|
|
||||||
class TestWindows:
|
class TestWindows:
|
||||||
|
|
||||||
def test_kitchen_window_count(self, plan1: MagicPlanPlan) -> None:
|
def test_kitchen_window_count(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan1.floors[0].rooms[0].windows) == 1
|
assert len(plan1.floors[0].rooms[0].windows) == 1
|
||||||
|
|
||||||
def test_corridor_window_count_zero(self, plan3: MagicPlanPlan) -> None:
|
def test_corridor_window_count_zero(self, plan3: MagicPlanXMLPlan) -> None:
|
||||||
corridor = plan3.floors[0].rooms[0]
|
corridor = plan3.floors[0].rooms[0]
|
||||||
assert corridor.type == "Corridor"
|
assert corridor.type == "Corridor"
|
||||||
assert len(corridor.windows) == 0
|
assert len(corridor.windows) == 0
|
||||||
|
|
||||||
def test_window_wall_point_index(self, plan1: MagicPlanPlan) -> None:
|
def test_window_wall_point_index(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].windows[0].wall_point_index == 1
|
assert plan1.floors[0].rooms[0].windows[0].wall_point_index == 1
|
||||||
|
|
||||||
def test_window_type(self, plan1: MagicPlanPlan) -> None:
|
def test_window_type(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].windows[0].type == "1"
|
assert plan1.floors[0].rooms[0].windows[0].type == "1"
|
||||||
|
|
||||||
def test_window_u(self, plan1: MagicPlanPlan) -> None:
|
def test_window_u(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].windows[0].u, 0.68463)
|
assert math.isclose(plan1.floors[0].rooms[0].windows[0].u, 0.68463)
|
||||||
|
|
||||||
def test_window_snapped_width(self, plan1: MagicPlanPlan) -> None:
|
def test_window_snapped_width(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].windows[0].snapped_width, 1.71972)
|
assert math.isclose(plan1.floors[0].rooms[0].windows[0].snapped_width, 1.71972)
|
||||||
|
|
||||||
def test_window_snapped_height(self, plan1: MagicPlanPlan) -> None:
|
def test_window_snapped_height(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].rooms[0].windows[0].snapped_height, 0.94940)
|
assert math.isclose(plan1.floors[0].rooms[0].windows[0].snapped_height, 0.94940)
|
||||||
|
|
||||||
def test_window_symbol_instance(self, plan1: MagicPlanPlan) -> None:
|
def test_window_symbol_instance(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].rooms[0].windows[0].symbol_instance == "W-0-2"
|
assert plan1.floors[0].rooms[0].windows[0].symbol_instance == "W-0-2"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -333,18 +333,18 @@ class TestWindows:
|
||||||
|
|
||||||
class TestRoomFurniture:
|
class TestRoomFurniture:
|
||||||
|
|
||||||
def test_kitchen_furniture_count(self, plan1: MagicPlanPlan) -> None:
|
def test_kitchen_furniture_count(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan1.floors[0].rooms[0].furniture) == 5
|
assert len(plan1.floors[0].rooms[0].furniture) == 5
|
||||||
|
|
||||||
def test_bathroom_furniture_count_zero(self, plan1: MagicPlanPlan) -> None:
|
def test_bathroom_furniture_count_zero(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
bathroom = plan1.floors[1].rooms[0]
|
bathroom = plan1.floors[1].rooms[0]
|
||||||
assert bathroom.type == "Bathroom"
|
assert bathroom.type == "Bathroom"
|
||||||
assert len(bathroom.furniture) == 0
|
assert len(bathroom.furniture) == 0
|
||||||
|
|
||||||
def test_furniture_type(self, plan1: MagicPlanPlan) -> None:
|
def test_furniture_type(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert isinstance(plan1.floors[0].rooms[0].furniture[0].type, str)
|
assert isinstance(plan1.floors[0].rooms[0].furniture[0].type, str)
|
||||||
|
|
||||||
def test_furniture_symbol_instance(self, plan1: MagicPlanPlan) -> None:
|
def test_furniture_symbol_instance(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert isinstance(plan1.floors[0].rooms[0].furniture[0].symbol_instance, str)
|
assert isinstance(plan1.floors[0].rooms[0].furniture[0].symbol_instance, str)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -354,16 +354,16 @@ class TestRoomFurniture:
|
||||||
|
|
||||||
class TestFloorLevelFurniture:
|
class TestFloorLevelFurniture:
|
||||||
|
|
||||||
def test_floor_furniture_count(self, plan3: MagicPlanPlan) -> None:
|
def test_floor_furniture_count(self, plan3: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan3.floors[0].furniture) == 1
|
assert len(plan3.floors[0].furniture) == 1
|
||||||
|
|
||||||
def test_floor_furniture_x(self, plan3: MagicPlanPlan) -> None:
|
def test_floor_furniture_x(self, plan3: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan3.floors[0].furniture[0].x, -2.09376)
|
assert math.isclose(plan3.floors[0].furniture[0].x, -2.09376)
|
||||||
|
|
||||||
def test_floor_furniture_y(self, plan3: MagicPlanPlan) -> None:
|
def test_floor_furniture_y(self, plan3: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan3.floors[0].furniture[0].y, 3.13664)
|
assert math.isclose(plan3.floors[0].furniture[0].y, 3.13664)
|
||||||
|
|
||||||
def test_floor_furniture_absent_plan1(self, plan1: MagicPlanPlan) -> None:
|
def test_floor_furniture_absent_plan1(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan1.floors[0].furniture) == 0
|
assert len(plan1.floors[0].furniture) == 0
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -373,13 +373,13 @@ class TestFloorLevelFurniture:
|
||||||
|
|
||||||
class TestMainDimensions:
|
class TestMainDimensions:
|
||||||
|
|
||||||
def test_main_dimension_count(self, plan1: MagicPlanPlan) -> None:
|
def test_main_dimension_count(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan1.floors[0].rooms[0].main_dimensions) == 2
|
assert len(plan1.floors[0].rooms[0].main_dimensions) == 2
|
||||||
|
|
||||||
def test_main_dimension_from_point(self, plan1: MagicPlanPlan) -> None:
|
def test_main_dimension_from_point(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert isinstance(plan1.floors[0].rooms[0].main_dimensions[0].from_point, int)
|
assert isinstance(plan1.floors[0].rooms[0].main_dimensions[0].from_point, int)
|
||||||
|
|
||||||
def test_main_dimension_is_set(self, plan1: MagicPlanPlan) -> None:
|
def test_main_dimension_is_set(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert isinstance(plan1.floors[0].rooms[0].main_dimensions[0].is_set, bool)
|
assert isinstance(plan1.floors[0].rooms[0].main_dimensions[0].is_set, bool)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -389,59 +389,59 @@ class TestMainDimensions:
|
||||||
|
|
||||||
class TestExploded:
|
class TestExploded:
|
||||||
|
|
||||||
def test_exploded_wall_count_ground_floor(self, plan1: MagicPlanPlan) -> None:
|
def test_exploded_wall_count_ground_floor(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan1.floors[0].exploded.walls) == 11
|
assert len(plan1.floors[0].exploded.walls) == 11
|
||||||
|
|
||||||
def test_exploded_door_count_ground_floor(self, plan1: MagicPlanPlan) -> None:
|
def test_exploded_door_count_ground_floor(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan1.floors[0].exploded.doors) == 6
|
assert len(plan1.floors[0].exploded.doors) == 6
|
||||||
|
|
||||||
def test_exploded_window_count_ground_floor(self, plan1: MagicPlanPlan) -> None:
|
def test_exploded_window_count_ground_floor(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan1.floors[0].exploded.windows) == 2
|
assert len(plan1.floors[0].exploded.windows) == 2
|
||||||
|
|
||||||
def test_exploded_wall_type(self, plan1: MagicPlanPlan) -> None:
|
def test_exploded_wall_type(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].exploded.walls[0].wall_type == "exterior"
|
assert plan1.floors[0].exploded.walls[0].wall_type == "exterior"
|
||||||
|
|
||||||
def test_exploded_wall_points(self, plan1: MagicPlanPlan) -> None:
|
def test_exploded_wall_points(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
pts = plan1.floors[0].exploded.walls[0].points
|
pts = plan1.floors[0].exploded.walls[0].points
|
||||||
assert len(pts) == 2
|
assert len(pts) == 2
|
||||||
assert math.isclose(pts[0].x, 2.363)
|
assert math.isclose(pts[0].x, 2.363)
|
||||||
assert math.isclose(pts[0].y, -1.778)
|
assert math.isclose(pts[0].y, -1.778)
|
||||||
assert math.isclose(pts[0].height, 2.323164)
|
assert math.isclose(pts[0].height, 2.323164)
|
||||||
|
|
||||||
def test_exploded_door_x1(self, plan1: MagicPlanPlan) -> None:
|
def test_exploded_door_x1(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].exploded.doors[0].x1, 5.24973)
|
assert math.isclose(plan1.floors[0].exploded.doors[0].x1, 5.24973)
|
||||||
|
|
||||||
def test_exploded_door_y1(self, plan1: MagicPlanPlan) -> None:
|
def test_exploded_door_y1(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].exploded.doors[0].y1, -1.333153)
|
assert math.isclose(plan1.floors[0].exploded.doors[0].y1, -1.333153)
|
||||||
|
|
||||||
def test_exploded_door_width(self, plan1: MagicPlanPlan) -> None:
|
def test_exploded_door_width(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].exploded.doors[0].width, 0.773)
|
assert math.isclose(plan1.floors[0].exploded.doors[0].width, 0.773)
|
||||||
|
|
||||||
def test_exploded_door_height(self, plan1: MagicPlanPlan) -> None:
|
def test_exploded_door_height(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].exploded.doors[0].height, 2.02225)
|
assert math.isclose(plan1.floors[0].exploded.doors[0].height, 2.02225)
|
||||||
|
|
||||||
def test_exploded_door_symbol_instance(self, plan1: MagicPlanPlan) -> None:
|
def test_exploded_door_symbol_instance(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].exploded.doors[0].symbol_instance == "W-0-1"
|
assert plan1.floors[0].exploded.doors[0].symbol_instance == "W-0-1"
|
||||||
|
|
||||||
def test_exploded_window_x1(self, plan1: MagicPlanPlan) -> None:
|
def test_exploded_window_x1(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].exploded.windows[0].x1, 5.24973)
|
assert math.isclose(plan1.floors[0].exploded.windows[0].x1, 5.24973)
|
||||||
|
|
||||||
def test_exploded_window_width(self, plan1: MagicPlanPlan) -> None:
|
def test_exploded_window_width(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].exploded.windows[0].width, 1.71972)
|
assert math.isclose(plan1.floors[0].exploded.windows[0].width, 1.71972)
|
||||||
|
|
||||||
def test_exploded_window_height(self, plan1: MagicPlanPlan) -> None:
|
def test_exploded_window_height(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert math.isclose(plan1.floors[0].exploded.windows[0].height, 0.949396)
|
assert math.isclose(plan1.floors[0].exploded.windows[0].height, 0.949396)
|
||||||
|
|
||||||
def test_exploded_window_symbol_instance(self, plan1: MagicPlanPlan) -> None:
|
def test_exploded_window_symbol_instance(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.floors[0].exploded.windows[0].symbol_instance == "W-0-2"
|
assert plan1.floors[0].exploded.windows[0].symbol_instance == "W-0-2"
|
||||||
|
|
||||||
def test_plan3_exploded_wall_count(self, plan3: MagicPlanPlan) -> None:
|
def test_plan3_exploded_wall_count(self, plan3: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan3.floors[0].exploded.walls) == 33
|
assert len(plan3.floors[0].exploded.walls) == 33
|
||||||
|
|
||||||
def test_plan3_exploded_door_count(self, plan3: MagicPlanPlan) -> None:
|
def test_plan3_exploded_door_count(self, plan3: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan3.floors[0].exploded.doors) == 12
|
assert len(plan3.floors[0].exploded.doors) == 12
|
||||||
|
|
||||||
def test_plan3_exploded_window_count(self, plan3: MagicPlanPlan) -> None:
|
def test_plan3_exploded_window_count(self, plan3: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan3.floors[0].exploded.windows) == 5
|
assert len(plan3.floors[0].exploded.windows) == 5
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -451,11 +451,11 @@ class TestExploded:
|
||||||
|
|
||||||
class TestInteriorRoomPoints:
|
class TestInteriorRoomPoints:
|
||||||
|
|
||||||
def test_interior_room_floor_count_plan1(self, plan1: MagicPlanPlan) -> None:
|
def test_interior_room_floor_count_plan1(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan1.interior_room_floors) == 2
|
assert len(plan1.interior_room_floors) == 2
|
||||||
|
|
||||||
def test_interior_room_floor_count_plan2(self, plan2: MagicPlanPlan) -> None:
|
def test_interior_room_floor_count_plan2(self, plan2: MagicPlanXMLPlan) -> None:
|
||||||
assert len(plan2.interior_room_floors) == 1
|
assert len(plan2.interior_room_floors) == 1
|
||||||
|
|
||||||
def test_interior_room_floor_uid_matches(self, plan1: MagicPlanPlan) -> None:
|
def test_interior_room_floor_uid_matches(self, plan1: MagicPlanXMLPlan) -> None:
|
||||||
assert plan1.interior_room_floors[0].uid == plan1.floors[0].uid
|
assert plan1.interior_room_floors[0].uid == plan1.floors[0].uid
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
from backend.magic_plan.models import (
|
from backend.magic_plan.models import (
|
||||||
MagicPlanDoor,
|
MagicPlanXMLDoor,
|
||||||
MagicPlanExploded,
|
MagicPlanXMLExploded,
|
||||||
MagicPlanExplodedOpening,
|
MagicPlanXMLExplodedOpening,
|
||||||
MagicPlanExplodedWall,
|
MagicPlanXMLExplodedWall,
|
||||||
MagicPlanFloor,
|
MagicPlanXMLFloor,
|
||||||
MagicPlanFurniture,
|
MagicPlanXMLFurniture,
|
||||||
MagicPlanMainDimension,
|
MagicPlanXMLMainDimension,
|
||||||
MagicPlanPlan,
|
MagicPlanXMLPlan,
|
||||||
MagicPlanRoom,
|
MagicPlanXMLRoom,
|
||||||
MagicPlanRoomPoint,
|
MagicPlanXMLRoomPoint,
|
||||||
MagicPlanSymbolInstance,
|
MagicPlanXMLSymbolInstance,
|
||||||
MagicPlanWallPoint,
|
MagicPlanXMLWallPoint,
|
||||||
MagicPlanWindow,
|
MagicPlanXMLWindow,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -21,8 +21,8 @@ def _values(el: ET.Element) -> dict[str, str]:
|
||||||
return {v.get("key", ""): (v.text or "") for v in el.findall("values/value")}
|
return {v.get("key", ""): (v.text or "") for v in el.findall("values/value")}
|
||||||
|
|
||||||
|
|
||||||
def _parse_room_point(el: ET.Element) -> MagicPlanRoomPoint:
|
def _parse_room_point(el: ET.Element) -> MagicPlanXMLRoomPoint:
|
||||||
return MagicPlanRoomPoint(
|
return MagicPlanXMLRoomPoint(
|
||||||
snapped_x=float(el.get("snappedX", "0")),
|
snapped_x=float(el.get("snappedX", "0")),
|
||||||
snapped_y=float(el.get("snappedY", "0")),
|
snapped_y=float(el.get("snappedY", "0")),
|
||||||
height=float(el.get("height", "0")),
|
height=float(el.get("height", "0")),
|
||||||
|
|
@ -31,16 +31,16 @@ def _parse_room_point(el: ET.Element) -> MagicPlanRoomPoint:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _parse_wall_point(el: ET.Element) -> MagicPlanWallPoint:
|
def _parse_wall_point(el: ET.Element) -> MagicPlanXMLWallPoint:
|
||||||
return MagicPlanWallPoint(
|
return MagicPlanXMLWallPoint(
|
||||||
x=float(el.get("x", "0")),
|
x=float(el.get("x", "0")),
|
||||||
y=float(el.get("y", "0")),
|
y=float(el.get("y", "0")),
|
||||||
height=float(el.get("height", "0")),
|
height=float(el.get("height", "0")),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _parse_door(el: ET.Element) -> MagicPlanDoor:
|
def _parse_door(el: ET.Element) -> MagicPlanXMLDoor:
|
||||||
return MagicPlanDoor(
|
return MagicPlanXMLDoor(
|
||||||
wall_point_index=int(el.get("point", "0")),
|
wall_point_index=int(el.get("point", "0")),
|
||||||
type=el.get("type", ""),
|
type=el.get("type", ""),
|
||||||
u=float(el.get("u", "0")),
|
u=float(el.get("u", "0")),
|
||||||
|
|
@ -62,8 +62,8 @@ def _parse_door(el: ET.Element) -> MagicPlanDoor:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _parse_window(el: ET.Element) -> MagicPlanWindow:
|
def _parse_window(el: ET.Element) -> MagicPlanXMLWindow:
|
||||||
return MagicPlanWindow(
|
return MagicPlanXMLWindow(
|
||||||
wall_point_index=int(el.get("point", "0")),
|
wall_point_index=int(el.get("point", "0")),
|
||||||
type=el.get("type", ""),
|
type=el.get("type", ""),
|
||||||
u=float(el.get("u", "0")),
|
u=float(el.get("u", "0")),
|
||||||
|
|
@ -84,8 +84,8 @@ def _parse_window(el: ET.Element) -> MagicPlanWindow:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _parse_exploded_opening(el: ET.Element) -> MagicPlanExplodedOpening:
|
def _parse_exploded_opening(el: ET.Element) -> MagicPlanXMLExplodedOpening:
|
||||||
return MagicPlanExplodedOpening(
|
return MagicPlanXMLExplodedOpening(
|
||||||
type=el.get("type", ""),
|
type=el.get("type", ""),
|
||||||
x1=float(el.get("x1", "0")),
|
x1=float(el.get("x1", "0")),
|
||||||
y1=float(el.get("y1", "0")),
|
y1=float(el.get("y1", "0")),
|
||||||
|
|
@ -101,8 +101,8 @@ def _parse_exploded_opening(el: ET.Element) -> MagicPlanExplodedOpening:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _parse_furniture(el: ET.Element) -> MagicPlanFurniture:
|
def _parse_furniture(el: ET.Element) -> MagicPlanXMLFurniture:
|
||||||
return MagicPlanFurniture(
|
return MagicPlanXMLFurniture(
|
||||||
type=el.get("type", ""),
|
type=el.get("type", ""),
|
||||||
x=float(el.get("x", "0")),
|
x=float(el.get("x", "0")),
|
||||||
y=float(el.get("y", "0")),
|
y=float(el.get("y", "0")),
|
||||||
|
|
@ -122,8 +122,8 @@ def _parse_furniture(el: ET.Element) -> MagicPlanFurniture:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _parse_main_dimension(el: ET.Element) -> MagicPlanMainDimension:
|
def _parse_main_dimension(el: ET.Element) -> MagicPlanXMLMainDimension:
|
||||||
return MagicPlanMainDimension(
|
return MagicPlanXMLMainDimension(
|
||||||
from_point=int(el.get("from", "0")),
|
from_point=int(el.get("from", "0")),
|
||||||
to_point=int(el.get("to", "0")),
|
to_point=int(el.get("to", "0")),
|
||||||
dir_x=float(el.get("dir.x", "0")),
|
dir_x=float(el.get("dir.x", "0")),
|
||||||
|
|
@ -134,16 +134,16 @@ def _parse_main_dimension(el: ET.Element) -> MagicPlanMainDimension:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _parse_exploded_wall(el: ET.Element) -> MagicPlanExplodedWall:
|
def _parse_exploded_wall(el: ET.Element) -> MagicPlanXMLExplodedWall:
|
||||||
type_el = el.find("type")
|
type_el = el.find("type")
|
||||||
return MagicPlanExplodedWall(
|
return MagicPlanXMLExplodedWall(
|
||||||
wall_type=(type_el.text or "") if type_el is not None else "",
|
wall_type=(type_el.text or "") if type_el is not None else "",
|
||||||
points=[_parse_wall_point(p) for p in el.findall("point")],
|
points=[_parse_wall_point(p) for p in el.findall("point")],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _parse_exploded(el: ET.Element) -> MagicPlanExploded:
|
def _parse_exploded(el: ET.Element) -> MagicPlanXMLExploded:
|
||||||
return MagicPlanExploded(
|
return MagicPlanXMLExploded(
|
||||||
walls=[_parse_exploded_wall(w) for w in el.findall("wall")],
|
walls=[_parse_exploded_wall(w) for w in el.findall("wall")],
|
||||||
doors=[_parse_exploded_opening(d) for d in el.findall("door")],
|
doors=[_parse_exploded_opening(d) for d in el.findall("door")],
|
||||||
windows=[_parse_exploded_opening(w) for w in el.findall("window")],
|
windows=[_parse_exploded_opening(w) for w in el.findall("window")],
|
||||||
|
|
@ -151,8 +151,8 @@ def _parse_exploded(el: ET.Element) -> MagicPlanExploded:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _parse_symbol_instance(el: ET.Element) -> MagicPlanSymbolInstance:
|
def _parse_symbol_instance(el: ET.Element) -> MagicPlanXMLSymbolInstance:
|
||||||
return MagicPlanSymbolInstance(
|
return MagicPlanXMLSymbolInstance(
|
||||||
id=el.get("id", ""),
|
id=el.get("id", ""),
|
||||||
uid=el.get("uid", ""),
|
uid=el.get("uid", ""),
|
||||||
parent_uid=el.get("parentUid", ""),
|
parent_uid=el.get("parentUid", ""),
|
||||||
|
|
@ -161,10 +161,10 @@ def _parse_symbol_instance(el: ET.Element) -> MagicPlanSymbolInstance:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _parse_floor(el: ET.Element) -> MagicPlanFloor:
|
def _parse_floor(el: ET.Element) -> MagicPlanXMLFloor:
|
||||||
si_el = el.find("symbolInstance")
|
si_el = el.find("symbolInstance")
|
||||||
exploded_el = el.find("exploded")
|
exploded_el = el.find("exploded")
|
||||||
return MagicPlanFloor(
|
return MagicPlanXMLFloor(
|
||||||
uid=el.get("uid", ""),
|
uid=el.get("uid", ""),
|
||||||
name=el.findtext("name") or "",
|
name=el.findtext("name") or "",
|
||||||
floor_type=el.get("floorType", "0"),
|
floor_type=el.get("floorType", "0"),
|
||||||
|
|
@ -174,16 +174,16 @@ def _parse_floor(el: ET.Element) -> MagicPlanFloor:
|
||||||
area_with_interior_walls_only=float(el.get("areaWithInteriorWallsOnly", "0")),
|
area_with_interior_walls_only=float(el.get("areaWithInteriorWallsOnly", "0")),
|
||||||
area_with_walls=float(el.get("areaWithWalls", "0")),
|
area_with_walls=float(el.get("areaWithWalls", "0")),
|
||||||
symbol_instance=_parse_symbol_instance(si_el) if si_el is not None
|
symbol_instance=_parse_symbol_instance(si_el) if si_el is not None
|
||||||
else MagicPlanSymbolInstance(id="", uid="", parent_uid="", symbol="", values={}),
|
else MagicPlanXMLSymbolInstance(id="", uid="", parent_uid="", symbol="", values={}),
|
||||||
rooms=[_parse_room(r) for r in el.findall("floorRoom")],
|
rooms=[_parse_room(r) for r in el.findall("floorRoom")],
|
||||||
furniture=[_parse_furniture(f) for f in el.findall("furniture")],
|
furniture=[_parse_furniture(f) for f in el.findall("furniture")],
|
||||||
exploded=_parse_exploded(exploded_el) if exploded_el is not None
|
exploded=_parse_exploded(exploded_el) if exploded_el is not None
|
||||||
else MagicPlanExploded(walls=[], doors=[], windows=[], furniture=[]),
|
else MagicPlanXMLExploded(walls=[], doors=[], windows=[], furniture=[]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _parse_room(el: ET.Element) -> MagicPlanRoom:
|
def _parse_room(el: ET.Element) -> MagicPlanXMLRoom:
|
||||||
return MagicPlanRoom(
|
return MagicPlanXMLRoom(
|
||||||
uid=el.get("uid", ""),
|
uid=el.get("uid", ""),
|
||||||
type=el.get("type", ""),
|
type=el.get("type", ""),
|
||||||
x=float(el.get("x", "0")),
|
x=float(el.get("x", "0")),
|
||||||
|
|
@ -203,10 +203,10 @@ def _parse_room(el: ET.Element) -> MagicPlanRoom:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def parse_magicplan_xml(xml_str: str) -> MagicPlanPlan:
|
def parse_magicplan_xml(xml_str: str) -> MagicPlanXMLPlan:
|
||||||
root = ET.fromstring(xml_str)
|
root = ET.fromstring(xml_str)
|
||||||
irp_el = root.find("interiorRoomPoints")
|
irp_el = root.find("interiorRoomPoints")
|
||||||
return MagicPlanPlan(
|
return MagicPlanXMLPlan(
|
||||||
id=root.get("id", ""),
|
id=root.get("id", ""),
|
||||||
uid=root.get("uid", ""),
|
uid=root.get("uid", ""),
|
||||||
name=root.get("name", ""),
|
name=root.get("name", ""),
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue