Skip to content

Commit

Permalink
typehints
Browse files Browse the repository at this point in the history
  • Loading branch information
JaskRendix committed Jan 22, 2024
1 parent 320de11 commit 0745b18
Showing 1 changed file with 36 additions and 30 deletions.
66 changes: 36 additions & 30 deletions pytmx/pytmx.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from itertools import chain, product
from math import cos, radians, sin
from operator import attrgetter
from typing import Optional, Union
from typing import DefaultDict, Optional, Union
from xml.etree import ElementTree

# for type hinting
Expand Down Expand Up @@ -74,11 +74,11 @@
'Cannot set user {} property on {} "{}"; Tiled property already exists.'
)

flag_names = ("flipped_horizontally", "flipped_vertically", "flipped_diagonally")

AnimationFrame = namedtuple("AnimationFrame", ["gid", "duration"])
Point = namedtuple("Point", ["x", "y"])
TileFlags = namedtuple("TileFlags", flag_names)
TileFlags = namedtuple(
"TileFlags", ("flipped_horizontally", "flipped_vertically", "flipped_diagonally")
)
empty_flags = TileFlags(False, False, False)
ColorLike = Union[tuple[int, int, int, int], tuple[int, int, int], int, str]
MapPoint = tuple[int, int, int]
Expand Down Expand Up @@ -505,19 +505,24 @@ def __init__(
# allow duplicate names to be parsed and loaded
TiledElement.allow_duplicate_names = kwargs.get("allow_duplicate_names", False)

self.layers: list[TiledLayer] = [] # all layers in proper order
self.tilesets: list[TiledTileset] = [] # TiledTileset objects
self.tile_properties = dict() # tiles that have properties
self.layernames = dict()
self.objects_by_id = dict()
self.objects_by_name = dict()
# all layers in proper order
self.layers: list[TiledLayer] = []
# TiledTileset objects
self.tilesets: list[TiledTileset] = []
# tiles that have properties
self.tile_properties: dict[int, dict[str, str]] = {}
self.layernames: dict[str, TiledLayer] = {}
self.objects_by_id: dict[str, TiledObject] = {}
self.objects_by_name: dict[int, TiledObject] = {}

# only used tiles are actually loaded, so there will be a difference
# between the GIDs in the Tiled map data (tmx) and the data in this
# object and the layers. This dictionary keeps track of that.
self.gidmap = defaultdict(list)
self.imagemap = dict() # mapping of gid and trans flags to real gids
self.tiledgidmap = dict() # mapping of tiledgid to pytmx gid
self.gidmap: DefaultDict[int, list[tuple[int, TileFlags]]] = defaultdict()
# mapping of gid and trans flags to real gids
self.imagemap: dict[tuple[int, TileFlags], tuple[int, TileFlags]] = {}
# mapping of tiledgid to pytmx gid
self.tiledgidmap: dict[int, int] = {}
self.maxgid = 1

# should be filled in by a loader function
Expand All @@ -541,7 +546,7 @@ def __init__(
self.custom_types = dict()

# initialize the gid mapping
self.imagemap[(0, 0)] = 0
self.imagemap[(0, TileFlags(0, 0, 0))] = (0, TileFlags(0, 0, 0))

if custom_property_filename:
self.parse_json(json.load(open(custom_property_filename)))
Expand Down Expand Up @@ -811,7 +816,9 @@ def get_tile_gid(self, x: int, y: int, layer: int) -> int:
logger.debug(msg.format(x, y, layer))
raise ValueError(msg.format(x, y, layer))

def get_tile_properties(self, x: int, y: int, layer: int) -> Optional[dict]:
def get_tile_properties(
self, x: int, y: int, layer: int
) -> Optional[dict[str, str]]:
"""Return the tile image GID for this location.
Args:
Expand Down Expand Up @@ -866,7 +873,7 @@ def get_tile_locations_by_gid(self, gid: int) -> Iterable[MapPoint]:
for x, y, _gid in [i for i in self.layers[l].iter_data() if i[2] == gid]:
yield x, y, l

def get_tile_properties_by_gid(self, gid: int) -> Optional[dict]:
def get_tile_properties_by_gid(self, gid: int) -> Optional[dict[str, str]]:
"""Get the tile properties of a tile GID.
Args:
Expand All @@ -881,7 +888,7 @@ def get_tile_properties_by_gid(self, gid: int) -> Optional[dict]:
except KeyError:
return None

def set_tile_properties(self, gid: int, properties: dict) -> None:
def set_tile_properties(self, gid: int, properties: dict[str, str]) -> None:
"""Set the tile properties of a tile GID.
Args:
Expand Down Expand Up @@ -933,6 +940,7 @@ def add_layer(
)

self.layers.append(layer)
assert layer.name
self.layernames[layer.name] = layer

def add_tileset(self, tileset: TiledTileset) -> None:
Expand Down Expand Up @@ -1011,7 +1019,7 @@ def get_tileset_from_gid(self, gid: int) -> TiledTileset:

raise ValueError("Tileset not found")

def get_tile_colliders(self) -> Iterable[tuple[int, list[dict]]]:
def get_tile_colliders(self) -> Iterable[tuple[int, str]]:
"""Return iterator of (gid, dict) pairs of tiles with colliders.
Returns:
Expand Down Expand Up @@ -1140,7 +1148,7 @@ def register_gid_check_flags(
else:
return self.register_gid(*decode_gid(tiled_gid))

def map_gid(self, tiled_gid: int) -> Optional[list[int]]:
def map_gid(self, tiled_gid: int) -> Optional[list[tuple[int, TileFlags]]]:
"""Used to lookup a GID read from a TMX file's data.
Args:
Expand All @@ -1151,18 +1159,16 @@ def map_gid(self, tiled_gid: int) -> Optional[list[int]]:
"""
try:
return self.gidmap[int(tiled_gid)]
return self.gidmap[tiled_gid]
except KeyError:
return None
except TypeError:
msg = "GIDs must be an integer"
logger.debug(msg)
raise TypeError(msg)

def map_gid2(self, tiled_gid: int) -> list[tuple[int, Optional[int]]]:
def map_gid2(self, tiled_gid: int) -> list[tuple[int, Optional[TileFlags]]]:
"""WIP. need to refactor the gid code"""
tiled_gid = int(tiled_gid)

# gidmap is a default dict, so cannot trust to raise KeyError
if tiled_gid in self.gidmap:
return self.gidmap[tiled_gid]
Expand Down Expand Up @@ -1227,7 +1233,7 @@ def parse_xml(self, node: ElementTree.Element) -> TiledTileset:
if source:
if source[-4:].lower() == ".tsx":
# external tilesets don't save this, store it for later
self.firstgid = int(node.get("firstgid"))
self.firstgid = int(node.get("firstgid", 0))

# we need to mangle the path - tiled stores relative paths
dirname = os.path.dirname(self.parent.filename)
Expand Down Expand Up @@ -1257,7 +1263,7 @@ def parse_xml(self, node: ElementTree.Element) -> TiledTileset:
# we store it separately in the parent (a TiledMap instance)
register_gid = self.parent.register_gid
for child in node.iter("tile"):
tiled_gid = int(child.get("id"))
tiled_gid = int(child.get("id", 0))

p = {k: types[k](v) for k, v in child.items()}
p.update(parse_properties(child))
Expand All @@ -1269,17 +1275,17 @@ def parse_xml(self, node: ElementTree.Element) -> TiledTileset:
# handle tiles that have their own image
image = child.find("image")
if image is None:
p["width"] = self.tilewidth
p["height"] = self.tileheight
p["width"] = str(self.tilewidth)
p["height"] = str(self.tileheight)
else:
tile_source = image.get("source")
# images are listed as relative to the .tsx file, not the .tmx file:
if source and tile_source:
tile_source = os.path.join(os.path.dirname(source), tile_source)
p["source"] = tile_source
p["trans"] = image.get("trans", None)
p["width"] = image.get("width", None)
p["height"] = image.get("height", None)
p["width"] = image.get("width", "0")
p["height"] = image.get("height", "0")

# handle tiles with animations
anim = child.find("animation")
Expand All @@ -1288,7 +1294,7 @@ def parse_xml(self, node: ElementTree.Element) -> TiledTileset:
if anim is not None:
for frame in anim.findall("frame"):
duration = int(frame.get("duration", 0))
gid = register_gid(int(frame.get("tileid")) + self.firstgid)
gid = register_gid(int(frame.get("tileid", 0)) + self.firstgid)
frames.append(AnimationFrame(gid, duration))

for objgrp_node in child.findall("objectgroup"):
Expand Down

0 comments on commit 0745b18

Please sign in to comment.