I'm back!

This commit is contained in:
Benjamin Kirkbride
2019-06-29 15:53:30 -04:00
parent a44c3523d4
commit 5b62df0409
14 changed files with 454 additions and 219 deletions

View File

@@ -1,3 +0,0 @@
[style]
based_on_style = google
column_limit = 78

View File

@@ -1,4 +1,5 @@
-e .
black
pytest
sphinx
coverage

21
mypy.ini Normal file
View File

@@ -0,0 +1,21 @@
# Global options:
[mypy]
python_version = 3.6
warn_unused_configs = False
disallow_any_unimported = True
disallow_any_expr = True
disallow_any_decorated = True
disallow_any_explicit = True
disallow_any_generics = True
disallow_subclassing_any = True
disallow_untyped_calls = True
disallow_untyped_defs = True
disallow_incomplete_defs = True
check_untyped_defs = True
disallow_untyped_decorators = True
warn_return_any = True
# Per-module options:
[mypy-tests.*]
ignore_errors = True

View File

@@ -2,16 +2,15 @@
pytiled_parser objects for Tiled maps.
"""
import dataclasses
import functools
import re
import xml.etree.ElementTree as etree
from collections import OrderedDict
from pathlib import Path
from typing import Dict, List, NamedTuple, Optional, Union
import xml.etree.ElementTree as etree
from typing import NamedTuple, Union, Optional, List, Dict
import attr
class Color(NamedTuple):
@@ -60,7 +59,7 @@ class Template:
"""
@dataclasses.dataclass
@attr.s(auto_attribs=True)
class Chunk:
"""
Chunk object for infinite maps.
@@ -81,7 +80,7 @@ class Chunk:
chunk_data: List[List[int]]
@dataclasses.dataclass
@attr.s(auto_attribs=True)
class Image:
"""
Image object.
@@ -100,7 +99,7 @@ class Image:
source: str
size: Optional[Size] = None
trans: Optional[Color] = None
trans: Optional[str] = None
Properties = Dict[str, Union[int, float, Color, Path, str]]
@@ -151,7 +150,7 @@ class Frame(NamedTuple):
duration: int
@dataclasses.dataclass
@attr.s(auto_attribs=True)
class TileTerrain:
"""
Defines each corner of a tile by Terrain index in
@@ -172,7 +171,7 @@ class TileTerrain:
bottom_right: Optional[int] = None
@dataclasses.dataclass
@attr.s(auto_attribs=True, kw_only=True)
class Layer:
"""Class that all layers inherret from.
@@ -212,7 +211,7 @@ Either a 2 dimensional array of integers representing the global tile IDs
"""
@dataclasses.dataclass
@attr.s(auto_attribs=True, kw_only=True)
class TileLayer(Layer):
"""Tile map layer containing tiles.
@@ -230,27 +229,8 @@ class TileLayer(Layer):
data: LayerData
@dataclasses.dataclass
class _TiledObjectBase:
id: int
location: OrderedPair
@dataclasses.dataclass
class _TiledObjectDefaults:
size: Size = Size(0, 0)
rotation: int = 0
opacity: float = 1
name: Optional[str] = None
type: Optional[str] = None
properties: Optional[Properties] = None
template: Optional[Template] = None
@dataclasses.dataclass
class TiledObject(_TiledObjectDefaults, _TiledObjectBase):
@attr.s(auto_attribs=True, kw_only=True)
class TiledObject:
"""
TiledObject object.
@@ -274,8 +254,21 @@ class TiledObject(_TiledObjectDefaults, _TiledObjectBase):
FIXME
"""
id: int
location: OrderedPair
@dataclasses.dataclass
size: Size = Size(0, 0)
rotation: int = 0
opacity: float = 1
name: Optional[str] = None
type: Optional[str] = None
properties: Optional[Properties] = None
template: Optional[Template] = None
@attr.s()
class RectangleObject(TiledObject):
"""
Rectangle shape defined by a point, width, and height.
@@ -286,7 +279,7 @@ class RectangleObject(TiledObject):
"""
@dataclasses.dataclass
@attr.s()
class ElipseObject(TiledObject):
"""
Elipse shape defined by a point, width, and height.
@@ -295,7 +288,7 @@ class ElipseObject(TiledObject):
"""
@dataclasses.dataclass
@attr.s()
class PointObject(TiledObject):
"""
Point defined by a point (x,y).
@@ -304,13 +297,8 @@ class PointObject(TiledObject):
"""
@dataclasses.dataclass
class _TileImageObjectBase(_TiledObjectBase):
gid: int
@dataclasses.dataclass
class TileImageObject(TiledObject, _TileImageObjectBase):
@attr.s(auto_attribs=True, kw_only=True)
class TileImageObject(TiledObject):
"""
Polygon shape defined by a set of connections between points.
@@ -320,14 +308,11 @@ class TileImageObject(TiledObject, _TileImageObjectBase):
:gid (int): Refference to a global tile id.
"""
@dataclasses.dataclass
class _PointsObjectBase(_TiledObjectBase):
points: List[OrderedPair]
gid: int
@dataclasses.dataclass
class PolygonObject(TiledObject, _PointsObjectBase):
@attr.s(auto_attribs=True, kw_only=True)
class PolygonObject(TiledObject):
"""
Polygon shape defined by a set of connections between points.
@@ -337,9 +322,11 @@ class PolygonObject(TiledObject, _PointsObjectBase):
:points (List[OrderedPair])
"""
points: List[OrderedPair]
@dataclasses.dataclass
class PolylineObject(TiledObject, _PointsObjectBase):
@attr.s(auto_attribs=True, kw_only=True)
class PolylineObject(TiledObject):
"""
Polyline defined by a set of connections between points.
@@ -351,29 +338,11 @@ class PolylineObject(TiledObject, _PointsObjectBase):
the location of the object.
"""
@dataclasses.dataclass
class _TextObjectBase(_TiledObjectBase):
text: str
points: List[OrderedPair]
@dataclasses.dataclass
class _TextObjectDefaults(_TiledObjectDefaults):
font_family: str = "sans-serif"
font_size: int = 16
wrap: bool = False
color: str = "#000000"
bold: bool = False
italic: bool = False
underline: bool = False
strike_out: bool = False
kerning: bool = False
horizontal_align: str = "left"
vertical_align: str = "top"
@dataclasses.dataclass
class TextObject(TiledObject, _TextObjectDefaults, _TextObjectBase):
@attr.s(auto_attribs=True, kw_only=True)
class TextObject(TiledObject):
"""
Text object with associated settings.
@@ -396,8 +365,21 @@ class TextObject(TiledObject, _TextObjectDefaults, _TextObjectBase):
:vertical_align (str): Vertical alignment of the text (defalt: "top")
"""
text: str
font_family: str = "sans-serif"
font_size: int = 16
wrap: bool = False
color: str = "#000000"
bold: bool = False
italic: bool = False
underline: bool = False
strike_out: bool = False
kerning: bool = False
horizontal_align: str = "left"
vertical_align: str = "top"
@dataclasses.dataclass
@attr.s(auto_attribs=True, kw_only=True)
class ObjectLayer(Layer):
"""
TiledObject Group Object.
@@ -426,7 +408,7 @@ class ObjectLayer(Layer):
draw_order: Optional[str] = "topdown"
@dataclasses.dataclass
@attr.s(auto_attribs=True, kw_only=True)
class LayerGroup(Layer):
"""
Layer Group.
@@ -445,13 +427,13 @@ class LayerGroup(Layer):
layers: Optional[List[Union["LayerGroup", Layer, ObjectLayer]]]
@dataclasses.dataclass
@attr.s(auto_attribs=True)
class Hitbox:
"""Group of hitboxes for
"""Group of hitboxes for FIXME
"""
@dataclasses.dataclass
@attr.s(auto_attribs=True)
class Tile:
"""
Individual tile object.
@@ -466,14 +448,15 @@ class Tile:
"""
id: int
type: Optional[str]
terrain: Optional[TileTerrain]
animation: Optional[List[Frame]]
image: Optional[Image]
hitboxes: Optional[List[TiledObject]]
type: Optional[str] = None
terrain: Optional[TileTerrain] = None
animation: Optional[List[Frame]] = None
image: Optional[Image] = None
hitboxes: Optional[List[TiledObject]] = None
@dataclasses.dataclass
@attr.s(auto_attribs=True)
class TileSet:
"""
Object for storing a TSX with all associated collision data.
@@ -506,22 +489,23 @@ class TileSet:
name: str
max_tile_size: Size
spacing: Optional[int]
margin: Optional[int]
tile_count: Optional[int]
columns: Optional[int]
tile_offset: Optional[OrderedPair]
grid: Optional[Grid]
properties: Optional[Properties]
image: Optional[Image]
terrain_types: Optional[List[Terrain]]
tiles: Optional[Dict[int, Tile]]
spacing: Optional[int] = None
margin: Optional[int] = None
tile_count: Optional[int] = None
columns: Optional[int] = None
tile_offset: Optional[OrderedPair] = None
grid: Optional[Grid] = None
properties: Optional[Properties] = None
image: Optional[Image] = None
terrain_types: Optional[List[Terrain]] = None
tiles: Optional[Dict[int, Tile]] = None
TileSetDict = Dict[int, TileSet]
@dataclasses.dataclass
@attr.s(auto_attribs=True)
class TileMap:
"""
Object for storing a TMX with all associated layers and properties.
@@ -569,7 +553,7 @@ class TileMap:
map_size: Size
tile_size: Size
infinite: bool
next_layer_id: int
next_layer_id: Optional[int]
next_object_id: int
tile_sets: TileSetDict
@@ -581,22 +565,3 @@ class TileMap:
background_color: Optional[str] = None
properties: Optional[Properties] = None
"""
[22:16] <__m4ch1n3__> i would "[i for i in int_list if i < littler_then_value]"
[22:16] <__m4ch1n3__> it returns a list of integers below "littler_then_value"
[22:17] <__m4ch1n3__> !py3 [i for i in [1,2,3,4,1,2,3,4] if i < 3]
[22:17] <codebot> __m4ch1n3__: [1, 2, 1, 2]
[22:17] <__m4ch1n3__> !py3 [i for i in [1,2,3,4,1,2,3,4] if i < 4]
[22:17] <codebot> __m4ch1n3__: [1, 2, 3, 1, 2, 3]
[22:22] <__m4ch1n3__> !py3 max([i for i in [1,2,3,4,1,2,3,4] if i < 4])
[22:22] <codebot> __m4ch1n3__: 3
[22:22] <__m4ch1n3__> max(...) would return the maximum of resulting list
[22:23] <__m4ch1n3__> !py3 max([i for i in [1, 10, 100] if i < 20])
[22:23] <codebot> __m4ch1n3__: 10
[22:23] <__m4ch1n3__> !py3 max([i for i in [1, 10, 100] if i < 242])
[22:23] <codebot> __m4ch1n3__: 100
[22:23] == markb1 [~mbiggers@45.36.35.206] has quit [Ping timeout: 245 seconds]
[22:23] <__m4ch1n3__> !py3 max(i for i in [1, 10, 100] if i < 242)
"""

View File

@@ -1,3 +1,6 @@
import functools
from typing import Dict, List, Optional
import pytiled_parser.objects as objects
@@ -27,8 +30,24 @@ def parse_color(color: str) -> objects.Color:
return objects.Color(red, green, blue, alpha)
def get_tile_by_gid(tile_sets: objects.TileSetDict, gid: int) -> objects.Tile:
"""Gets Tile from a global tile ID.
def _get_tile_set_key(gid: int, tile_set_keys: List[int]) -> int:
"""Gets tile set key given a tile GID.
Args:
gid: Global ID of the tile.
Returns:
int: The key of the tile set that contains the tile for the GID.
"""
# credit to __m4ch1n3__ on ##learnpython for this idea
return max([key for key in tile_set_keys if key <= gid])
def get_tile_by_gid(
gid: int, tile_sets: objects.TileSetDict
) -> Optional[objects.Tile]:
"""Gets correct Tile for a given global ID.
Args:
tile_sets (objects.TileSetDict): TileSetDict from TileMap.
@@ -36,10 +55,13 @@ def get_tile_by_gid(tile_sets: objects.TileSetDict, gid: int) -> objects.Tile:
Returns:
objects.Tile: The Tile object reffered to by the global tile ID.
None: If there is no objects.Tile object in the tile_set.tiles dict
for the associated gid.
"""
for tileset_key, tileset in tile_sets.items():
for tile_key, tile in tileset.tiles.items():
tile_gid = tile.id + tileset_key
if tile_gid == gid:
return tile
tile_set_key = _get_tile_set_key(gid, list(tile_sets.keys()))
tile_set = tile_sets[tile_set_key]
if tile_set.tiles is not None:
return tile_set.tiles.get(gid - tile_set_key)
return None

View File

@@ -1,13 +1,11 @@
import functools
import base64
import functools
import gzip
import re
import zlib
from pathlib import Path
from typing import Callable, Dict, List, Optional, Tuple, Union
import xml.etree.ElementTree as etree
import zlib
from pathlib import Path
from typing import Callable, Dict, List, Optional, Tuple, Union
import pytiled_parser.objects as objects
import pytiled_parser.utilities as utilities
@@ -73,7 +71,7 @@ def _decode_data(
element: etree.Element,
layer_width: int,
encoding: str,
compression: Optional[str],
compression: Optional[str] = None,
) -> List[List[int]]:
"""Decodes data or chunk data.
@@ -105,12 +103,10 @@ def _decode_data(
if encoding == "csv":
return _decode_csv_data(data_text)
return _decode_base64_data(data_text, compression, layer_width)
return _decode_base64_data(data_text, layer_width, compression)
def _parse_data(
element: etree.Element, layer_width: int
) -> objects.LayerData:
def _parse_data(element: etree.Element, layer_width: int) -> objects.LayerData:
"""Parses layer data.
Will parse CSV, base64, gzip-base64, or zlip-base64 encoded data.
@@ -226,7 +222,13 @@ def _parse_tile_layer(element: etree.Element,) -> objects.TileLayer:
raise ValueError(f"{element} has no child data element.")
return objects.TileLayer(
id, name, offset, opacity, properties, size, data
id=id,
name=name,
offset=offset,
opacity=opacity,
properties=properties,
size=size,
data=data,
)
@@ -249,7 +251,7 @@ def _parse_objects(
location_y = float(object_element.attrib["y"])
location = objects.OrderedPair(location_x, location_y)
tiled_object = objects.TiledObject(id, location)
tiled_object = objects.TiledObject(id=id, location=location)
try:
width = float(object_element.attrib["width"])
@@ -323,14 +325,14 @@ def _parse_object_layer(element: etree.Element,) -> objects.ObjectLayer:
pass
return objects.ObjectLayer(
id,
name,
offset,
opacity,
properties,
tiled_objects,
color,
draw_order,
id=id,
name=name,
offset=offset,
opacity=opacity,
properties=properties,
tiled_objects=tiled_objects,
color=color,
draw_order=draw_order,
)
@@ -352,7 +354,14 @@ def _parse_layer_group(element: etree.Element,) -> objects.LayerGroup:
layers = _get_layers(element)
return objects.LayerGroup(id, name, offset, opacity, properties, layers)
return objects.LayerGroup(
id=id,
name=name,
offset=offset,
opacity=opacity,
properties=properties,
layers=layers,
)
def _get_layer_parser(
@@ -648,6 +657,37 @@ def _parse_tile_set(tile_set_element: etree.Element) -> objects.TileSet:
)
def _get_tile_sets(
map_element: etree.Element, parent_dir: Path
) -> objects.TileSetDict:
# parse all tilesets
tile_sets: objects.TileSetDict = {}
tile_set_element_list = map_element.findall("./tileset")
for tile_set_element in tile_set_element_list:
# tiled docs are ambiguous about the 'firstgid' attribute
# current understanding is for the purposes of mapping the layer
# data to the tile set data, add the 'firstgid' value to each
# tile 'id'; this means that the 'firstgid' is specific to each,
# tile set as they pertain to the map, not tile set specific as
# the tiled docs can make it seem
# 'firstgid' the key for each TileMap
first_gid = int(tile_set_element.attrib["firstgid"])
try:
# check if is an external TSX
source = tile_set_element.attrib["source"]
except KeyError:
# the tile set in embedded
name = tile_set_element.attrib["name"]
tile_sets[first_gid] = _parse_tile_set(tile_set_element)
else:
# tile set is external
tile_sets[first_gid] = _parse_external_tile_set(
parent_dir, tile_set_element
)
return tile_sets
def parse_tile_map(tmx_file: Union[str, Path]) -> objects.TileMap:
# setting up XML parsing
map_tree = etree.parse(str(tmx_file))
@@ -660,9 +700,11 @@ def parse_tile_map(tmx_file: Union[str, Path]) -> objects.TileMap:
tiled_version = map_element.attrib["tiledversion"]
orientation = map_element.attrib["orientation"]
render_order = map_element.attrib["renderorder"]
map_width = int(map_element.attrib["width"])
map_height = int(map_element.attrib["height"])
map_size = objects.Size(map_width, map_height)
tile_width = int(map_element.attrib["tilewidth"])
tile_height = int(map_element.attrib["tileheight"])
tile_size = objects.Size(tile_width, tile_height)
@@ -673,30 +715,7 @@ def parse_tile_map(tmx_file: Union[str, Path]) -> objects.TileMap:
next_layer_id = int(map_element.attrib["nextlayerid"])
next_object_id = int(map_element.attrib["nextobjectid"])
# parse all tilesets
tile_sets: Dict[int, objects.TileSet] = {}
tile_set_element_list = map_element.findall("./tileset")
for tile_set_element in tile_set_element_list:
# tiled docs are ambiguous about the 'firstgid' attribute
# current understanding is for the purposes of mapping the layer
# data to the tile set data, add the 'firstgid' value to each
# tile 'id'; this means that the 'firstgid' is specific to each,
# tile set as they pertain to the map, not tile set specific as
# the tiled docs can make it seem
# 'firstgid' is saved beside each TileMap
firstgid = int(tile_set_element.attrib["firstgid"])
try:
# check if is an external TSX
source = tile_set_element.attrib["source"]
except KeyError:
# the tile set in embedded
name = tile_set_element.attrib["name"]
tile_sets[firstgid] = _parse_tile_set(tile_set_element)
else:
# tile set is external
tile_sets[firstgid] = _parse_external_tile_set(
parent_dir, tile_set_element
)
tile_sets = _get_tile_sets(map_element, parent_dir)
layers = _get_layers(map_element)

View File

@@ -1,6 +1,7 @@
from os import path
import sys
from setuptools import setup
from os import path
from setuptools import setup # type: ignore
BUILD = 0
VERSION = "0.0.1"
@@ -21,7 +22,7 @@ if __name__ == "__main__":
license="MIT",
url="https://github.com/Beefy-Swain/pytiled_parser",
download_url="https://github.com/Beefy-Swain/pytiled_parser",
install_requires=["dataclasses"],
install_requires=["attrs"],
packages=["pytiled_parser"],
classifiers=[
"Development Status :: 1 - Planning",

View File

@@ -1,20 +0,0 @@
{ 'background_color': None,
'hex_side_length': None,
'infinite': False,
'layers': [ TileLayer(id=1, name='Tile Layer 1', offset=None, opacity=None, properties=None, size=Size(width=10, height=10), data=[[1, 2, 3, 4, 5, 6, 7, 8, 30, 30], [9, 10, 11, 12, 13, 14, 15, 16, 30, 30], [17, 18, 19, 20, 21, 22, 23, 24, 30, 30], [25, 26, 27, 28, 29, 30, 31, 32, 30, 30], [33, 34, 35, 36, 37, 38, 39, 40, 30, 30], [41, 42, 43, 44, 45, 46, 47, 48, 30, 30], [30, 30, 30, 30, 30, 30, 30, 30, 30, 30], [30, 30, 30, 30, 30, 30, 30, 30, 30, 30], [30, 30, 30, 30, 30, 30, 30, 30, 30, 30], [30, 30, 30, 30, 30, 30, 30, 30, 30, 30]]),
TileLayer(id=2, name='Tile Layer 2', offset=None, opacity=0.5, properties=None, size=Size(width=10, height=10), data=[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 46, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 6, 7, 7, 7, 7, 7, 8, 0], [0, 0, 14, 15, 15, 15, 15, 15, 16, 0], [0, 0, 22, 23, 23, 23, 23, 23, 24, 0]]),
LayerGroup(id=3, name='Group 1', offset=None, opacity=None, properties={'bool property': True}, layers=[TileLayer(id=5, name='Tile Layer 4', offset=OrderedPair(x=49.0, y=-50.0), opacity=None, properties=None, size=Size(width=10, height=10), data=[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 31, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]), TileLayer(id=4, name='Tile Layer 3', offset=None, opacity=None, properties=None, size=Size(width=10, height=10), data=[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 2, 3, 0, 0, 0, 0, 0, 0, 0], [9, 10, 11, 0, 0, 0, 0, 0, 0, 0], [17, 18, 19, 0, 0, 0, 0, 0, 0, 0]])]),
ObjectLayer(id=6, name='Object Layer 1', offset=OrderedPair(x=4.66667, y=-4.33333), opacity=0.9, properties=None, tiled_objects=[TiledObject(id=1, location=OrderedPair(x=200.25, y=210.75), size=Size(width=47.25, height=25.0), rotation=15, opacity=1, name='rectangle 1', type='rectangle type', properties=None, template=None), TiledObject(id=2, location=OrderedPair(x=252.5, y=87.75), size=Size(width=0, height=0), rotation=-21, opacity=1, name='polygon 1', type='polygon type', properties=None, template=None), TiledObject(id=3, location=OrderedPair(x=198.75, y=102.5), size=Size(width=17.75, height=14.25), rotation=0, opacity=1, name='elipse 1', type='elipse type', properties=None, template=None), TiledObject(id=4, location=OrderedPair(x=174.25, y=186.0), size=Size(width=0, height=0), rotation=0, opacity=1, name='point 1', type='point type', properties=None, template=None), TiledObject(id=7, location=OrderedPair(x=11.3958, y=48.5833), size=Size(width=107.625, height=27.25), rotation=0, opacity=1, name='insert text 1', type='insert text type', properties=None, template=None), TiledObject(id=6, location=OrderedPair(x=47.25, y=72.5), size=Size(width=47.0, height=53.0), rotation=31, opacity=1, name='inserted tile 1', type='inserted tile type', properties={'tile property bool': True}, template=None), TiledObject(id=8, location=OrderedPair(x=144.667, y=112.0), size=Size(width=0, height=0), rotation=0, opacity=1, name='polyline 1', type='polyline type', properties=None, template=None), TiledObject(id=9, location=OrderedPair(x=69.8333, y=168.333), size=Size(width=0, height=0), rotation=0, opacity=1, name='polygon 2', type='polygon type', properties=None, template=None)], color=Color(red=0, green=0, blue=0, alpha=255), draw_order='index')],
'map_size': Size(width=10, height=10),
'next_layer_id': 16,
'next_object_id': 10,
'orientation': 'orthogonal',
'parent_dir': PosixPath('/home/benk/Projects/pytiled_parser/venv/pytiled_parser/tests/test_data'),
'properties': None,
'render_order': 'right-down',
'stagger_axis': None,
'stagger_index': None,
'tile_sets': { 1: TileSet(name='tile_set_image', max_tile_size=Size(width=32, height=32), spacing=1, margin=1, tile_count=48, columns=8, tile_offset=None, grid=None, properties=None, image=Image(source='images/tmw_desert_spacing.png', size=Size(width=265, height=199), trans=None), terrain_types=None, tiles={})},
'tile_size': Size(width=32, height=32),
'tiled_version': '1.2.3',
'version': '1.2'}

22
test/test_attr.py Normal file
View File

@@ -0,0 +1,22 @@
import attr
@attr.s(auto_attribs=True, kw_only=True)
class Foo:
x: int
y: int
a: int = 5
@attr.s(auto_attribs=True, kw_only=True)
class Bar(Foo):
z: int
foo = Foo(x=1, y=2)
bar = Bar(x=1, y=2, z=3)
print(foo)
print(bar)

178
test/test_output.py Normal file
View File

@@ -0,0 +1,178 @@
{
"parent_dir": PosixPath(
"/home/ben/Projects/pytiled_parser/pytiled_parser-venv/pytiled_parser/tests/test_data"
),
"version": "1.2",
"tiled_version": "1.2.3",
"orientation": "orthogonal",
"render_order": "right-down",
"map_size": Size(width=8, height=6),
"tile_size": Size(width=32, height=32),
"infinite": False,
"next_layer_id": 2,
"next_object_id": 1,
"tile_sets": {
1: TileSet(
name="tile_set_image",
max_tile_size=Size(width=32, height=32),
spacing=1,
margin=1,
tile_count=48,
columns=8,
tile_offset=None,
grid=None,
properties=None,
image=Image(
source="images/tmw_desert_spacing.png",
size=Size(width=265, height=199),
trans=None,
),
terrain_types=None,
tiles={
9: Tile(
id=9,
type=None,
terrain=None,
animation=None,
image=None,
hitboxes=[
TiledObject(
id=2,
location=OrderedPair(x=1.0, y=1.0),
size=Size(width=32.0, height=32.0),
rotation=1,
opacity=1,
name="wall",
type="rectangle type",
properties=None,
template=None,
)
],
),
19: Tile(
id=19,
type=None,
terrain=None,
animation=None,
image=None,
hitboxes=[
TiledObject(
id=1,
location=OrderedPair(x=32.0, y=1.0),
size=Size(width=0, height=0),
rotation=1,
opacity=1,
name="wall corner",
type="polygon type",
properties=None,
template=None,
)
],
),
20: Tile(
id=20,
type=None,
terrain=None,
animation=None,
image=None,
hitboxes=[
TiledObject(
id=1,
location=OrderedPair(x=1.45455, y=1.45455),
size=Size(width=0, height=0),
rotation=1,
opacity=1,
name="polyline",
type="polyline type",
properties=None,
template=None,
)
],
),
31: Tile(
id=31,
type=None,
terrain=None,
animation=None,
image=None,
hitboxes=[
TiledObject(
id=1,
location=OrderedPair(x=5.09091, y=2.54545),
size=Size(width=19.6364, height=19.2727),
rotation=1,
opacity=1,
name="rock 1",
type="elipse type",
properties=None,
template=None,
),
TiledObject(
id=2,
location=OrderedPair(x=16.1818, y=22.0),
size=Size(width=8.54545, height=8.36364),
rotation=-1,
opacity=1,
name="rock 2",
type="elipse type",
properties=None,
template=None,
),
],
),
45: Tile(
id=45,
type=None,
terrain=None,
animation=None,
image=None,
hitboxes=[
TiledObject(
id=1,
location=OrderedPair(x=14.7273, y=26.3636),
size=Size(width=0, height=0),
rotation=0,
opacity=1,
name="sign",
type="point type",
properties=None,
template=None,
)
],
),
},
)
},
"layers": [
TileLayer(
id=1,
name="Tile Layer 1",
offset=None,
opacity=None,
properties=None,
size=Size(width=8, height=6),
data=[
[1, 2, 3, 4, 5, 6, 7, 8],
[9, 10, 11, 12, 13, 14, 15, 16],
[17, 18, 19, 20, 21, 22, 23, 24],
[25, 26, 27, 28, 29, 30, 31, 32],
[33, 34, 35, 36, 37, 38, 39, 40],
[41, 42, 43, 44, 45, 46, 47, 48],
],
)
],
"hex_side_length": None,
"stagger_axis": None,
"stagger_index": None,
"background_color": None,
"properties": {
"bool property - false": False,
"bool property - true": True,
"color property": "#ff49fcff",
"file property": PosixPath("../../../../../../../../var/log/syslog"),
"float property": 1.23456789,
"int property": 13,
"string property": "Hello, World!!",
},
}
e

View File

@@ -1,17 +1,11 @@
import pprint
import pickle
import pprint
from io import StringIO
import pytiled_parser
pp = pprint.PrettyPrinter(indent=4, compact=True, width=100)
pp = pp.pprint
MAP_NAME = "/home/benk/Projects/pytiled_parser/venv/pytiled_parser/tests/test_data/test_map_image_tile_set.tmx"
MAP_NAME = "/home/ben/Projects/pytiled_parser/pytiled_parser-venv/pytiled_parser/tests/test_data/test_map_simple_hitboxes.tmx"
map = pytiled_parser.parse_tile_map(MAP_NAME)
pp(map.__dict__)
print(map.__dict__)

View File

@@ -1,3 +1,3 @@
import pytest
pytest.main(["-x", "tests/unit2"])
pytest.main(["--tb=native", "-s", "tests"])

View File

@@ -1,11 +1,9 @@
import pytest
import xml.etree.ElementTree as etree
from contextlib import contextmanager
from typing import Callable, List, Optional, Tuple
from pytiled_parser import objects, xml_parser, utilities
import pytest
from pytiled_parser import objects, utilities, xml_parser
@contextmanager
@@ -19,8 +17,7 @@ def _get_root_element(xml: str) -> etree.Element:
layer_data = [
(
'<layer id="1" name="Tile Layer 1" width="10" height="10">'
"</layer>",
'<layer id="1" name="Tile Layer 1" width="10" height="10">' "</layer>",
(int(1), "Tile Layer 1", None, None, None),
),
(
@@ -46,7 +43,7 @@ layer_data = [
@pytest.mark.parametrize("xml,expected", layer_data)
def test_parse_layer(xml, expected, monkeypatch):
def mockreturn(properties):
def mockreturn(*args):
return "properties"
monkeypatch.setattr(xml_parser, "_parse_properties_element", mockreturn)
@@ -160,11 +157,53 @@ data_base64 = [
@pytest.mark.parametrize(
"data_base64,width,compression,expected,raises", data_base64
)
def test_decode_base64_data(
data_base64, width, compression, expected, raises
):
def test_decode_base64_data(data_base64, width, compression, expected, raises):
with raises:
assert (
xml_parser._decode_base64_data(data_base64, width, compression)
== expected
)
# FIXME: use hypothesis for this
def create_tile_set(qty_of_tiles):
tile_set = objects.TileSet(None, None)
if qty_of_tiles == 0:
return tile_set
tiles = {}
for tile_id in range(qty_of_tiles):
tiles[tile_id] = objects.Tile(tile_id)
tile_set.tiles = tiles
return tile_set
tile_by_gid = [
(1, {1: create_tile_set(0)}, None),
(1, {1: create_tile_set(1)}, objects.Tile(0)),
(1, {1: create_tile_set(2)}, objects.Tile(0)),
(2, {1: create_tile_set(1)}, None),
(10, {1: create_tile_set(10)}, objects.Tile(9)),
(1, {1: create_tile_set(1), 2: create_tile_set(1)}, objects.Tile(0)),
(2, {1: create_tile_set(1), 2: create_tile_set(1)}, objects.Tile(0)),
(3, {1: create_tile_set(1), 2: create_tile_set(1)}, None),
(15, {1: create_tile_set(5), 6: create_tile_set(10)}, objects.Tile(9)),
(
20,
{
1: create_tile_set(5),
6: create_tile_set(10),
16: create_tile_set(10),
},
objects.Tile(4),
),
]
@pytest.mark.parametrize("gid,tile_sets,expected", tile_by_gid)
def test_get_tile_by_gid(gid, tile_sets, expected):
assert utilities.get_tile_by_gid(gid, tile_sets) == expected

View File

@@ -1,9 +1,7 @@
import os
from pathlib import Path
import pytest
import pytiled_parser
print(os.path.dirname(os.path.abspath(__file__)))
@@ -15,13 +13,11 @@ def test_map_simple():
"""
TMX with a very simple spritesheet tile set and some properties.
"""
map = pytiled_parser.parse_tile_map(
Path("../test_data/test_map_simple.tmx")
)
map = pytiled_parser.parse_tile_map(Path("test_data/test_map_simple.tmx"))
# map
# unsure how to get paths to compare propperly
assert str(map.parent_dir) == "../test_data"
assert str(map.parent_dir) == "test_data"
assert map.version == "1.2"
assert map.tiled_version == "1.2.3"
assert map.orientation == "orthogonal"
@@ -41,7 +37,7 @@ def test_map_simple():
assert map.properties == {
"bool property - false": False,
"bool property - true": True,
"color property": (0x49, 0xFC, 0xFF, 0xFF),
"color property": "#ff49fcff",
"file property": Path("/var/log/syslog"),
"float property": 1.23456789,
"int property": 13,