Re-run black formatting

This commit is contained in:
Darren Eberly
2023-02-19 17:38:39 -05:00
parent 117ef785ec
commit 6f3e903ba6
3 changed files with 662 additions and 664 deletions

View File

@@ -1,332 +1,332 @@
"""Object parsing for the JSON Map Format. """Object parsing for the JSON Map Format.
""" """
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Dict, List, Optional from typing import Any, Callable, Dict, List, Optional
from typing_extensions import TypedDict from typing_extensions import TypedDict
from pytiled_parser.common_types import OrderedPair, Size from pytiled_parser.common_types import OrderedPair, Size
from pytiled_parser.parsers.json.properties import RawProperty from pytiled_parser.parsers.json.properties import RawProperty
from pytiled_parser.parsers.json.properties import parse as parse_properties from pytiled_parser.parsers.json.properties import parse as parse_properties
from pytiled_parser.tiled_object import ( from pytiled_parser.tiled_object import (
Ellipse, Ellipse,
Point, Point,
Polygon, Polygon,
Polyline, Polyline,
Rectangle, Rectangle,
Text, Text,
Tile, Tile,
TiledObject, TiledObject,
) )
from pytiled_parser.util import load_object_template, parse_color from pytiled_parser.util import load_object_template, parse_color
RawText = TypedDict( RawText = TypedDict(
"RawText", "RawText",
{ {
"text": str, "text": str,
"color": str, "color": str,
"fontfamily": str, "fontfamily": str,
"pixelsize": float, # this is `font_size` in Text "pixelsize": float, # this is `font_size` in Text
"bold": bool, "bold": bool,
"italic": bool, "italic": bool,
"strikeout": bool, "strikeout": bool,
"underline": bool, "underline": bool,
"kerning": bool, "kerning": bool,
"halign": str, "halign": str,
"valign": str, "valign": str,
"wrap": bool, "wrap": bool,
}, },
) )
RawText.__doc__ = """ RawText.__doc__ = """
The keys and their types that appear in a Tiled JSON Text Object. The keys and their types that appear in a Tiled JSON Text Object.
Tiled Doc: https://doc.mapeditor.org/en/stable/reference/json-map-format/#text-example Tiled Doc: https://doc.mapeditor.org/en/stable/reference/json-map-format/#text-example
""" """
RawObject = TypedDict( RawObject = TypedDict(
"RawObject", "RawObject",
{ {
"id": int, "id": int,
"gid": int, "gid": int,
"template": str, "template": str,
"x": float, "x": float,
"y": float, "y": float,
"width": float, "width": float,
"height": float, "height": float,
"rotation": float, "rotation": float,
"visible": bool, "visible": bool,
"name": str, "name": str,
"class": str, "class": str,
"type": str, "type": str,
"properties": List[RawProperty], "properties": List[RawProperty],
"ellipse": bool, "ellipse": bool,
"point": bool, "point": bool,
"polygon": List[Dict[str, float]], "polygon": List[Dict[str, float]],
"polyline": List[Dict[str, float]], "polyline": List[Dict[str, float]],
"text": RawText, "text": RawText,
}, },
) )
RawObject.__doc__ = """ RawObject.__doc__ = """
The keys and their types that appear in a Tiled JSON Object. The keys and their types that appear in a Tiled JSON Object.
Tiled Doc: https://doc.mapeditor.org/en/stable/reference/json-map-format/#object Tiled Doc: https://doc.mapeditor.org/en/stable/reference/json-map-format/#object
""" """
def _parse_common(raw_object: RawObject) -> TiledObject: def _parse_common(raw_object: RawObject) -> TiledObject:
"""Create an Object containing all the attributes common to all types of objects. """Create an Object containing all the attributes common to all types of objects.
Args: Args:
raw_object: Raw object to get common attributes from raw_object: Raw object to get common attributes from
Returns: Returns:
Object: The attributes in common of all types of objects Object: The attributes in common of all types of objects
""" """
common = TiledObject( common = TiledObject(
id=raw_object["id"], id=raw_object["id"],
coordinates=OrderedPair(raw_object["x"], raw_object["y"]), coordinates=OrderedPair(raw_object["x"], raw_object["y"]),
visible=raw_object["visible"], visible=raw_object["visible"],
size=Size(raw_object["width"], raw_object["height"]), size=Size(raw_object["width"], raw_object["height"]),
rotation=raw_object["rotation"], rotation=raw_object["rotation"],
name=raw_object["name"], name=raw_object["name"],
) )
if raw_object.get("type") is not None: if raw_object.get("type") is not None:
common.class_ = raw_object["type"] common.class_ = raw_object["type"]
if raw_object.get("class") is not None: if raw_object.get("class") is not None:
common.class_ = raw_object["class"] common.class_ = raw_object["class"]
if raw_object.get("properties") is not None: if raw_object.get("properties") is not None:
common.properties = parse_properties(raw_object["properties"]) common.properties = parse_properties(raw_object["properties"])
return common return common
def _parse_ellipse(raw_object: RawObject) -> Ellipse: def _parse_ellipse(raw_object: RawObject) -> Ellipse:
"""Parse the raw object into an Ellipse. """Parse the raw object into an Ellipse.
Args: Args:
raw_object: Raw object to be parsed to an Ellipse raw_object: Raw object to be parsed to an Ellipse
Returns: Returns:
Ellipse: The Ellipse object created from the raw object Ellipse: The Ellipse object created from the raw object
""" """
return Ellipse(**_parse_common(raw_object).__dict__) return Ellipse(**_parse_common(raw_object).__dict__)
def _parse_rectangle(raw_object: RawObject) -> Rectangle: def _parse_rectangle(raw_object: RawObject) -> Rectangle:
"""Parse the raw object into a Rectangle. """Parse the raw object into a Rectangle.
Args: Args:
raw_object: Raw object to be parsed to a Rectangle raw_object: Raw object to be parsed to a Rectangle
Returns: Returns:
Rectangle: The Rectangle object created from the raw object Rectangle: The Rectangle object created from the raw object
""" """
return Rectangle(**_parse_common(raw_object).__dict__) return Rectangle(**_parse_common(raw_object).__dict__)
def _parse_point(raw_object: RawObject) -> Point: def _parse_point(raw_object: RawObject) -> Point:
"""Parse the raw object into a Point. """Parse the raw object into a Point.
Args: Args:
raw_object: Raw object to be parsed to a Point raw_object: Raw object to be parsed to a Point
Returns: Returns:
Point: The Point object created from the raw object Point: The Point object created from the raw object
""" """
return Point(**_parse_common(raw_object).__dict__) return Point(**_parse_common(raw_object).__dict__)
def _parse_polygon(raw_object: RawObject) -> Polygon: def _parse_polygon(raw_object: RawObject) -> Polygon:
"""Parse the raw object into a Polygon. """Parse the raw object into a Polygon.
Args: Args:
raw_object: Raw object to be parsed to a Polygon raw_object: Raw object to be parsed to a Polygon
Returns: Returns:
Polygon: The Polygon object created from the raw object Polygon: The Polygon object created from the raw object
""" """
polygon = [] polygon = []
for point in raw_object["polygon"]: for point in raw_object["polygon"]:
polygon.append(OrderedPair(point["x"], point["y"])) polygon.append(OrderedPair(point["x"], point["y"]))
return Polygon(points=polygon, **_parse_common(raw_object).__dict__) return Polygon(points=polygon, **_parse_common(raw_object).__dict__)
def _parse_polyline(raw_object: RawObject) -> Polyline: def _parse_polyline(raw_object: RawObject) -> Polyline:
"""Parse the raw object into a Polyline. """Parse the raw object into a Polyline.
Args: Args:
raw_object: Raw object to be parsed to a Polyline raw_object: Raw object to be parsed to a Polyline
Returns: Returns:
Polyline: The Polyline object created from the raw object Polyline: The Polyline object created from the raw object
""" """
polyline = [] polyline = []
for point in raw_object["polyline"]: for point in raw_object["polyline"]:
polyline.append(OrderedPair(point["x"], point["y"])) polyline.append(OrderedPair(point["x"], point["y"]))
return Polyline(points=polyline, **_parse_common(raw_object).__dict__) return Polyline(points=polyline, **_parse_common(raw_object).__dict__)
def _parse_tile( def _parse_tile(
raw_object: RawObject, raw_object: RawObject,
new_tileset: Optional[Dict[str, Any]] = None, new_tileset: Optional[Dict[str, Any]] = None,
new_tileset_path: Optional[Path] = None, new_tileset_path: Optional[Path] = None,
) -> Tile: ) -> Tile:
"""Parse the raw object into a Tile. """Parse the raw object into a Tile.
Args: Args:
raw_object: Raw object to be parsed to a Tile raw_object: Raw object to be parsed to a Tile
Returns: Returns:
Tile: The Tile object created from the raw object Tile: The Tile object created from the raw object
""" """
gid = raw_object["gid"] gid = raw_object["gid"]
return Tile( return Tile(
gid=gid, gid=gid,
new_tileset=new_tileset, new_tileset=new_tileset,
new_tileset_path=new_tileset_path, new_tileset_path=new_tileset_path,
**_parse_common(raw_object).__dict__ **_parse_common(raw_object).__dict__,
) )
def _parse_text(raw_object: RawObject) -> Text: def _parse_text(raw_object: RawObject) -> Text:
"""Parse the raw object into Text. """Parse the raw object into Text.
Args: Args:
raw_object: Raw object to be parsed to a Text raw_object: Raw object to be parsed to a Text
Returns: Returns:
Text: The Text object created from the raw object Text: The Text object created from the raw object
""" """
# required attributes # required attributes
raw_text: RawText = raw_object["text"] raw_text: RawText = raw_object["text"]
text = raw_text["text"] text = raw_text["text"]
# create base Text object # create base Text object
text_object = Text(text=text, **_parse_common(raw_object).__dict__) text_object = Text(text=text, **_parse_common(raw_object).__dict__)
# optional attributes # optional attributes
if raw_text.get("color") is not None: if raw_text.get("color") is not None:
text_object.color = parse_color(raw_text["color"]) text_object.color = parse_color(raw_text["color"])
if raw_text.get("fontfamily") is not None: if raw_text.get("fontfamily") is not None:
text_object.font_family = raw_text["fontfamily"] text_object.font_family = raw_text["fontfamily"]
if raw_text.get("pixelsize") is not None: if raw_text.get("pixelsize") is not None:
text_object.font_size = raw_text["pixelsize"] text_object.font_size = raw_text["pixelsize"]
if raw_text.get("bold") is not None: if raw_text.get("bold") is not None:
text_object.bold = raw_text["bold"] text_object.bold = raw_text["bold"]
if raw_text.get("italic") is not None: if raw_text.get("italic") is not None:
text_object.italic = raw_text["italic"] text_object.italic = raw_text["italic"]
if raw_text.get("kerning") is not None: if raw_text.get("kerning") is not None:
text_object.kerning = raw_text["kerning"] text_object.kerning = raw_text["kerning"]
if raw_text.get("strikeout") is not None: if raw_text.get("strikeout") is not None:
text_object.strike_out = raw_text["strikeout"] text_object.strike_out = raw_text["strikeout"]
if raw_text.get("underline") is not None: if raw_text.get("underline") is not None:
text_object.underline = raw_text["underline"] text_object.underline = raw_text["underline"]
if raw_text.get("halign") is not None: if raw_text.get("halign") is not None:
text_object.horizontal_align = raw_text["halign"] text_object.horizontal_align = raw_text["halign"]
if raw_text.get("valign") is not None: if raw_text.get("valign") is not None:
text_object.vertical_align = raw_text["valign"] text_object.vertical_align = raw_text["valign"]
if raw_text.get("wrap") is not None: if raw_text.get("wrap") is not None:
text_object.wrap = raw_text["wrap"] text_object.wrap = raw_text["wrap"]
return text_object return text_object
def _get_parser(raw_object: RawObject) -> Callable[[RawObject], TiledObject]: def _get_parser(raw_object: RawObject) -> Callable[[RawObject], TiledObject]:
"""Get the parser function for a given raw object. """Get the parser function for a given raw object.
Only used internally by the JSON parser. Only used internally by the JSON parser.
Args: Args:
raw_object: Raw object that is analyzed to determine the parser function. raw_object: Raw object that is analyzed to determine the parser function.
Returns: Returns:
Callable[[RawObject], Object]: The parser function. Callable[[RawObject], Object]: The parser function.
""" """
if raw_object.get("ellipse"): if raw_object.get("ellipse"):
return _parse_ellipse return _parse_ellipse
if raw_object.get("point"): if raw_object.get("point"):
return _parse_point return _parse_point
# This is excluded from tests because the coverage is broken. I promise # This is excluded from tests because the coverage is broken. I promise
# there are tests for Tile objects, but for some reason the coverage # there are tests for Tile objects, but for some reason the coverage
# isn't picking up this if statement(though it does pickup the _parse_tile) # isn't picking up this if statement(though it does pickup the _parse_tile)
# function so who knows # function so who knows
if raw_object.get("gid"): # pragma: no cover if raw_object.get("gid"): # pragma: no cover
# Only tile objects have the `gid` key # Only tile objects have the `gid` key
return _parse_tile return _parse_tile
if raw_object.get("polygon"): if raw_object.get("polygon"):
return _parse_polygon return _parse_polygon
if raw_object.get("polyline"): if raw_object.get("polyline"):
return _parse_polyline return _parse_polyline
if raw_object.get("text"): if raw_object.get("text"):
return _parse_text return _parse_text
# If it's none of the above, rectangle is the only one left. # If it's none of the above, rectangle is the only one left.
# Rectangle is the only object which has no special properties to signify that. # Rectangle is the only object which has no special properties to signify that.
return _parse_rectangle return _parse_rectangle
def parse( def parse(
raw_object: RawObject, raw_object: RawObject,
parent_dir: Optional[Path] = None, parent_dir: Optional[Path] = None,
) -> TiledObject: ) -> TiledObject:
"""Parse the raw object into a pytiled_parser version """Parse the raw object into a pytiled_parser version
Args: Args:
raw_object: Raw object that is to be cast. raw_object: Raw object that is to be cast.
parent_dir: The parent directory that the map file is in. parent_dir: The parent directory that the map file is in.
Returns: Returns:
Object: A parsed Object. Object: A parsed Object.
Raises: Raises:
RuntimeError: When a parameter that is conditionally required was not sent. RuntimeError: When a parameter that is conditionally required was not sent.
""" """
new_tileset = None new_tileset = None
new_tileset_path = None new_tileset_path = None
if raw_object.get("template"): if raw_object.get("template"):
if not parent_dir: if not parent_dir:
raise RuntimeError( raise RuntimeError(
"A parent directory must be specified when using object templates." "A parent directory must be specified when using object templates."
) )
template_path = Path(parent_dir / raw_object["template"]) template_path = Path(parent_dir / raw_object["template"])
template, new_tileset, new_tileset_path = load_object_template(template_path) template, new_tileset, new_tileset_path = load_object_template(template_path)
if isinstance(template, dict): if isinstance(template, dict):
loaded_template = template["object"] loaded_template = template["object"]
for key in loaded_template: for key in loaded_template:
if key != "id": if key != "id":
raw_object[key] = loaded_template[key] # type: ignore raw_object[key] = loaded_template[key] # type: ignore
else: else:
raise NotImplementedError( raise NotImplementedError(
"Loading TMX object templates inside a JSON map is currently not supported, " "Loading TMX object templates inside a JSON map is currently not supported, "
"but will be in a future release." "but will be in a future release."
) )
if raw_object.get("gid"): if raw_object.get("gid"):
return _parse_tile(raw_object, new_tileset, new_tileset_path) return _parse_tile(raw_object, new_tileset, new_tileset_path)
return _get_parser(raw_object)(raw_object) return _get_parser(raw_object)(raw_object)

View File

@@ -1,37 +1,35 @@
import xml.etree.ElementTree as etree import xml.etree.ElementTree as etree
from pathlib import Path from pathlib import Path
from pytiled_parser.properties import Properties, Property from pytiled_parser.properties import Properties, Property
from pytiled_parser.util import parse_color from pytiled_parser.util import parse_color
def parse(raw_properties: etree.Element) -> Properties: def parse(raw_properties: etree.Element) -> Properties:
final: Properties = {}
final: Properties = {} value: Property
value: Property
for raw_property in raw_properties.findall("property"):
for raw_property in raw_properties.findall("property"): type_ = raw_property.attrib.get("type")
type_ = raw_property.attrib.get("type") if "value" not in raw_property.attrib:
continue
if "value" not in raw_property.attrib:
continue value_ = raw_property.attrib["value"]
value_ = raw_property.attrib["value"] if type_ == "file":
value = Path(value_)
if type_ == "file": elif type_ == "color":
value = Path(value_) value = parse_color(value_)
elif type_ == "color": elif type_ == "int" or type_ == "float":
value = parse_color(value_) value = float(value_)
elif type_ == "int" or type_ == "float": elif type_ == "bool":
value = float(value_) if value_ == "true":
elif type_ == "bool": value = True
if value_ == "true": else:
value = True value = False
else: else:
value = False value = value_
else: final[raw_property.attrib["name"]] = value
value = value_
final[raw_property.attrib["name"]] = value return final
return final

View File

@@ -1,295 +1,295 @@
import xml.etree.ElementTree as etree import xml.etree.ElementTree as etree
from pathlib import Path from pathlib import Path
from typing import Callable, Optional from typing import Callable, Optional
from pytiled_parser.common_types import OrderedPair, Size from pytiled_parser.common_types import OrderedPair, Size
from pytiled_parser.parsers.tmx.properties import parse as parse_properties from pytiled_parser.parsers.tmx.properties import parse as parse_properties
from pytiled_parser.tiled_object import ( from pytiled_parser.tiled_object import (
Ellipse, Ellipse,
Point, Point,
Polygon, Polygon,
Polyline, Polyline,
Rectangle, Rectangle,
Text, Text,
Tile, Tile,
TiledObject, TiledObject,
) )
from pytiled_parser.util import load_object_template, parse_color from pytiled_parser.util import load_object_template, parse_color
def _parse_common(raw_object: etree.Element) -> TiledObject: def _parse_common(raw_object: etree.Element) -> TiledObject:
"""Create an Object containing all the attributes common to all types of objects. """Create an Object containing all the attributes common to all types of objects.
Args: Args:
raw_object: XML Element to get common attributes from raw_object: XML Element to get common attributes from
Returns: Returns:
Object: The attributes in common of all types of objects Object: The attributes in common of all types of objects
""" """
common = TiledObject( common = TiledObject(
id=int(raw_object.attrib["id"]), id=int(raw_object.attrib["id"]),
coordinates=OrderedPair( coordinates=OrderedPair(
float(raw_object.attrib["x"]), float(raw_object.attrib["y"]) float(raw_object.attrib["x"]), float(raw_object.attrib["y"])
), ),
) )
if raw_object.attrib.get("width") is not None: if raw_object.attrib.get("width") is not None:
common.size = Size( common.size = Size(
float(raw_object.attrib["width"]), float(raw_object.attrib["height"]) float(raw_object.attrib["width"]), float(raw_object.attrib["height"])
) )
if raw_object.attrib.get("visible") is not None: if raw_object.attrib.get("visible") is not None:
common.visible = bool(int(raw_object.attrib["visible"])) common.visible = bool(int(raw_object.attrib["visible"]))
if raw_object.attrib.get("rotation") is not None: if raw_object.attrib.get("rotation") is not None:
common.rotation = float(raw_object.attrib["rotation"]) common.rotation = float(raw_object.attrib["rotation"])
if raw_object.attrib.get("name") is not None: if raw_object.attrib.get("name") is not None:
common.name = raw_object.attrib["name"] common.name = raw_object.attrib["name"]
if raw_object.attrib.get("type") is not None: if raw_object.attrib.get("type") is not None:
common.class_ = raw_object.attrib["type"] common.class_ = raw_object.attrib["type"]
if raw_object.attrib.get("class") is not None: if raw_object.attrib.get("class") is not None:
common.class_ = raw_object.attrib["class"] common.class_ = raw_object.attrib["class"]
properties_element = raw_object.find("./properties") properties_element = raw_object.find("./properties")
if properties_element: if properties_element:
common.properties = parse_properties(properties_element) common.properties = parse_properties(properties_element)
return common return common
def _parse_ellipse(raw_object: etree.Element) -> Ellipse: def _parse_ellipse(raw_object: etree.Element) -> Ellipse:
"""Parse the raw object into an Ellipse. """Parse the raw object into an Ellipse.
Args: Args:
raw_object: XML Element to be parsed to an Ellipse raw_object: XML Element to be parsed to an Ellipse
Returns: Returns:
Ellipse: The Ellipse object created from the raw object Ellipse: The Ellipse object created from the raw object
""" """
return Ellipse(**_parse_common(raw_object).__dict__) return Ellipse(**_parse_common(raw_object).__dict__)
def _parse_rectangle(raw_object: etree.Element) -> Rectangle: def _parse_rectangle(raw_object: etree.Element) -> Rectangle:
"""Parse the raw object into a Rectangle. """Parse the raw object into a Rectangle.
Args: Args:
raw_object: XML Element to be parsed to a Rectangle raw_object: XML Element to be parsed to a Rectangle
Returns: Returns:
Rectangle: The Rectangle object created from the raw object Rectangle: The Rectangle object created from the raw object
""" """
return Rectangle(**_parse_common(raw_object).__dict__) return Rectangle(**_parse_common(raw_object).__dict__)
def _parse_point(raw_object: etree.Element) -> Point: def _parse_point(raw_object: etree.Element) -> Point:
"""Parse the raw object into a Point. """Parse the raw object into a Point.
Args: Args:
raw_object: XML Element to be parsed to a Point raw_object: XML Element to be parsed to a Point
Returns: Returns:
Point: The Point object created from the raw object Point: The Point object created from the raw object
""" """
return Point(**_parse_common(raw_object).__dict__) return Point(**_parse_common(raw_object).__dict__)
def _parse_polygon(raw_object: etree.Element) -> Polygon: def _parse_polygon(raw_object: etree.Element) -> Polygon:
"""Parse the raw object into a Polygon. """Parse the raw object into a Polygon.
Args: Args:
raw_object: XML Element to be parsed to a Polygon raw_object: XML Element to be parsed to a Polygon
Returns: Returns:
Polygon: The Polygon object created from the raw object Polygon: The Polygon object created from the raw object
""" """
polygon = [] polygon = []
polygon_element = raw_object.find("./polygon") polygon_element = raw_object.find("./polygon")
if polygon_element is not None: if polygon_element is not None:
for raw_point in polygon_element.attrib["points"].split(" "): for raw_point in polygon_element.attrib["points"].split(" "):
point = raw_point.split(",") point = raw_point.split(",")
polygon.append(OrderedPair(float(point[0]), float(point[1]))) polygon.append(OrderedPair(float(point[0]), float(point[1])))
return Polygon(points=polygon, **_parse_common(raw_object).__dict__) return Polygon(points=polygon, **_parse_common(raw_object).__dict__)
def _parse_polyline(raw_object: etree.Element) -> Polyline: def _parse_polyline(raw_object: etree.Element) -> Polyline:
"""Parse the raw object into a Polyline. """Parse the raw object into a Polyline.
Args: Args:
raw_object: Raw object to be parsed to a Polyline raw_object: Raw object to be parsed to a Polyline
Returns: Returns:
Polyline: The Polyline object created from the raw object Polyline: The Polyline object created from the raw object
""" """
polyline = [] polyline = []
polyline_element = raw_object.find("./polyline") polyline_element = raw_object.find("./polyline")
if polyline_element is not None: if polyline_element is not None:
for raw_point in polyline_element.attrib["points"].split(" "): for raw_point in polyline_element.attrib["points"].split(" "):
point = raw_point.split(",") point = raw_point.split(",")
polyline.append(OrderedPair(float(point[0]), float(point[1]))) polyline.append(OrderedPair(float(point[0]), float(point[1])))
return Polyline(points=polyline, **_parse_common(raw_object).__dict__) return Polyline(points=polyline, **_parse_common(raw_object).__dict__)
def _parse_tile( def _parse_tile(
raw_object: etree.Element, raw_object: etree.Element,
new_tileset: Optional[etree.Element] = None, new_tileset: Optional[etree.Element] = None,
new_tileset_path: Optional[Path] = None, new_tileset_path: Optional[Path] = None,
) -> Tile: ) -> Tile:
"""Parse the raw object into a Tile. """Parse the raw object into a Tile.
Args: Args:
raw_object: XML Element to be parsed to a Tile raw_object: XML Element to be parsed to a Tile
Returns: Returns:
Tile: The Tile object created from the raw object Tile: The Tile object created from the raw object
""" """
return Tile( return Tile(
gid=int(raw_object.attrib["gid"]), gid=int(raw_object.attrib["gid"]),
new_tileset=new_tileset, new_tileset=new_tileset,
new_tileset_path=new_tileset_path, new_tileset_path=new_tileset_path,
**_parse_common(raw_object).__dict__ **_parse_common(raw_object).__dict__,
) )
def _parse_text(raw_object: etree.Element) -> Text: def _parse_text(raw_object: etree.Element) -> Text:
"""Parse the raw object into Text. """Parse the raw object into Text.
Args: Args:
raw_object: XML Element to be parsed to a Text raw_object: XML Element to be parsed to a Text
Returns: Returns:
Text: The Text object created from the raw object Text: The Text object created from the raw object
""" """
# required attributes # required attributes
text_element = raw_object.find("./text") text_element = raw_object.find("./text")
if text_element is not None: if text_element is not None:
text = text_element.text text = text_element.text
if not text: if not text:
text = "" text = ""
# create base Text object # create base Text object
text_object = Text(text=text, **_parse_common(raw_object).__dict__) text_object = Text(text=text, **_parse_common(raw_object).__dict__)
# optional attributes # optional attributes
if text_element.attrib.get("color") is not None: if text_element.attrib.get("color") is not None:
text_object.color = parse_color(text_element.attrib["color"]) text_object.color = parse_color(text_element.attrib["color"])
if text_element.attrib.get("fontfamily") is not None: if text_element.attrib.get("fontfamily") is not None:
text_object.font_family = text_element.attrib["fontfamily"] text_object.font_family = text_element.attrib["fontfamily"]
if text_element.attrib.get("pixelsize") is not None: if text_element.attrib.get("pixelsize") is not None:
text_object.font_size = float(text_element.attrib["pixelsize"]) text_object.font_size = float(text_element.attrib["pixelsize"])
if text_element.attrib.get("bold") is not None: if text_element.attrib.get("bold") is not None:
text_object.bold = bool(int(text_element.attrib["bold"])) text_object.bold = bool(int(text_element.attrib["bold"]))
if text_element.attrib.get("italic") is not None: if text_element.attrib.get("italic") is not None:
text_object.italic = bool(int(text_element.attrib["italic"])) text_object.italic = bool(int(text_element.attrib["italic"]))
if text_element.attrib.get("kerning") is not None: if text_element.attrib.get("kerning") is not None:
text_object.kerning = bool(int(text_element.attrib["kerning"])) text_object.kerning = bool(int(text_element.attrib["kerning"]))
if text_element.attrib.get("strikeout") is not None: if text_element.attrib.get("strikeout") is not None:
text_object.strike_out = bool(int(text_element.attrib["strikeout"])) text_object.strike_out = bool(int(text_element.attrib["strikeout"]))
if text_element.attrib.get("underline") is not None: if text_element.attrib.get("underline") is not None:
text_object.underline = bool(int(text_element.attrib["underline"])) text_object.underline = bool(int(text_element.attrib["underline"]))
if text_element.attrib.get("halign") is not None: if text_element.attrib.get("halign") is not None:
text_object.horizontal_align = text_element.attrib["halign"] text_object.horizontal_align = text_element.attrib["halign"]
if text_element.attrib.get("valign") is not None: if text_element.attrib.get("valign") is not None:
text_object.vertical_align = text_element.attrib["valign"] text_object.vertical_align = text_element.attrib["valign"]
if text_element.attrib.get("wrap") is not None: if text_element.attrib.get("wrap") is not None:
text_object.wrap = bool(int(text_element.attrib["wrap"])) text_object.wrap = bool(int(text_element.attrib["wrap"]))
return text_object return text_object
def _get_parser(raw_object: etree.Element) -> Callable[[etree.Element], TiledObject]: def _get_parser(raw_object: etree.Element) -> Callable[[etree.Element], TiledObject]:
"""Get the parser function for a given raw object. """Get the parser function for a given raw object.
Only used internally by the TMX parser. Only used internally by the TMX parser.
Args: Args:
raw_object: XML Element that is analyzed to determine the parser function. raw_object: XML Element that is analyzed to determine the parser function.
Returns: Returns:
Callable[[Element], Object]: The parser function. Callable[[Element], Object]: The parser function.
""" """
if raw_object.find("./ellipse") is not None: if raw_object.find("./ellipse") is not None:
return _parse_ellipse return _parse_ellipse
if raw_object.find("./point") is not None: if raw_object.find("./point") is not None:
return _parse_point return _parse_point
if raw_object.find("./polygon") is not None: if raw_object.find("./polygon") is not None:
return _parse_polygon return _parse_polygon
if raw_object.find("./polyline") is not None: if raw_object.find("./polyline") is not None:
return _parse_polyline return _parse_polyline
if raw_object.find("./text") is not None: if raw_object.find("./text") is not None:
return _parse_text return _parse_text
# If it's none of the above, rectangle is the only one left. # If it's none of the above, rectangle is the only one left.
# Rectangle is the only object which has no properties to signify that. # Rectangle is the only object which has no properties to signify that.
return _parse_rectangle return _parse_rectangle
def parse(raw_object: etree.Element, parent_dir: Optional[Path] = None) -> TiledObject: def parse(raw_object: etree.Element, parent_dir: Optional[Path] = None) -> TiledObject:
"""Parse the raw object into a pytiled_parser version """Parse the raw object into a pytiled_parser version
Args: Args:
raw_object: XML Element that is to be parsed. raw_object: XML Element that is to be parsed.
parent_dir: The parent directory that the map file is in. parent_dir: The parent directory that the map file is in.
Returns: Returns:
TiledObject: A parsed Object. TiledObject: A parsed Object.
Raises: Raises:
RuntimeError: When a parameter that is conditionally required was not sent. RuntimeError: When a parameter that is conditionally required was not sent.
""" """
new_tileset = None new_tileset = None
new_tileset_path = None new_tileset_path = None
if raw_object.attrib.get("template"): if raw_object.attrib.get("template"):
if not parent_dir: if not parent_dir:
raise RuntimeError( raise RuntimeError(
"A parent directory must be specified when using object templates." "A parent directory must be specified when using object templates."
) )
template_path = Path(parent_dir / raw_object.attrib["template"]) template_path = Path(parent_dir / raw_object.attrib["template"])
template, new_tileset, new_tileset_path = load_object_template(template_path) template, new_tileset, new_tileset_path = load_object_template(template_path)
if isinstance(template, etree.Element): if isinstance(template, etree.Element):
new_object = template.find("./object") new_object = template.find("./object")
if new_object is not None: if new_object is not None:
if raw_object.attrib.get("id") is not None: if raw_object.attrib.get("id") is not None:
new_object.attrib["id"] = raw_object.attrib["id"] new_object.attrib["id"] = raw_object.attrib["id"]
if raw_object.attrib.get("x") is not None: if raw_object.attrib.get("x") is not None:
new_object.attrib["x"] = raw_object.attrib["x"] new_object.attrib["x"] = raw_object.attrib["x"]
if raw_object.attrib.get("y") is not None: if raw_object.attrib.get("y") is not None:
new_object.attrib["y"] = raw_object.attrib["y"] new_object.attrib["y"] = raw_object.attrib["y"]
raw_object = new_object raw_object = new_object
elif isinstance(template, dict): elif isinstance(template, dict):
# load the JSON object into the XML object # load the JSON object into the XML object
raise NotImplementedError( raise NotImplementedError(
"Loading JSON object templates inside a TMX map is currently not supported, " "Loading JSON object templates inside a TMX map is currently not supported, "
"but will be in a future release." "but will be in a future release."
) )
if raw_object.attrib.get("gid"): if raw_object.attrib.get("gid"):
return _parse_tile(raw_object, new_tileset, new_tileset_path) return _parse_tile(raw_object, new_tileset, new_tileset_path)
return _get_parser(raw_object)(raw_object) return _get_parser(raw_object)(raw_object)