Skip to content

Commit

Permalink
Merge pull request #3 from YajJackson/fix-type-issues
Browse files Browse the repository at this point in the history
fix type issues
  • Loading branch information
YajJackson authored Apr 13, 2024
2 parents 63a65ba + 9da15f8 commit c1af722
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 34 deletions.
3 changes: 3 additions & 0 deletions godot_parser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
from .objects import *
from .sections import *
from .tree import *
from beartype.claw import beartype_this_package

beartype_this_package()

__version__ = "0.1.7"

Expand Down
19 changes: 11 additions & 8 deletions godot_parser/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
Optional,
Sequence,
Type,
TypeVar,
Union,
cast,
)
Expand Down Expand Up @@ -39,9 +38,6 @@
]


GDFileType = TypeVar("GDFileType", bound="GDFile")


class GodotFileException(Exception):
"""Thrown when there are errors in a Godot file"""

Expand Down Expand Up @@ -259,7 +255,9 @@ def load_parent_scene(self) -> "GDScene":
raise RuntimeError(
"Could not find parent scene resource id(%d)" % root.instance
)
return GDScene.load(gdpath_to_filepath(self.project_root, parent_res.path))
scene = GDScene.load(gdpath_to_filepath(self.project_root, parent_res.path))
assert isinstance(scene, GDScene)
return scene

@contextmanager
def use_tree(self):
Expand Down Expand Up @@ -302,12 +300,12 @@ def get_node(self, path: str = ".") -> Optional[GDNodeSection]:
return node.section if node is not None else None

@classmethod
def parse(cls: Type[GDFileType], contents: str) -> GDFileType:
def parse(cls, contents: str):
"""Parse the contents of a Godot file"""
return cls.from_parser(scene_file.parse_string(contents, parseAll=True))

@classmethod
def load(cls: Type[GDFileType], filepath: str) -> GDFileType:
def load(cls, filepath: str):
with open(filepath, "r", encoding="utf-8") as ifile:
try:
file = cls.parse(ifile.read())
Expand All @@ -320,7 +318,7 @@ def load(cls: Type[GDFileType], filepath: str) -> GDFileType:
return file

@classmethod
def from_parser(cls: Type[GDFileType], parse_result):
def from_parser(cls, parse_result):
first_section = parse_result[0]
if first_section.header.name == "gd_scene":
scene = GDScene.__new__(GDScene)
Expand All @@ -330,6 +328,7 @@ def from_parser(cls: Type[GDFileType], parse_result):
resource = GDResource.__new__(GDResource)
resource._sections = list(parse_result)
return resource

return cls(*parse_result)

def write(self, filename: str):
Expand Down Expand Up @@ -382,6 +381,7 @@ def remove_at(self, index: int):
section = self._sections.pop(index)
if section.header.name in ["ext_resource", "sub_resource"]:
self.load_steps -= 1
return section

def remove_unused_resources(self):
self._remove_unused_resources(self.get_ext_resources(), ExtResource)
Expand Down Expand Up @@ -456,3 +456,6 @@ def __init__(self, *sections: GDSection) -> None:
class GDResource(GDCommonFile):
def __init__(self, *sections: GDSection) -> None:
super().__init__("gd_resource", *sections)


GDFileType = Union[GDFile, GDScene, GDResource]
1 change: 1 addition & 0 deletions godot_parser/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ def _load_parent_scene(root: Node, file: GDFile):
parent_file: GDFile = file.load_parent_scene()
parent_tree = Tree.build(parent_file)
# Transfer parent scene's children to this scene
assert parent_tree.root is not None, "Parent scene has no root node"
for child in parent_tree.root.get_children():
root.add_child(child)
# Mark the entire parent tree as inherited
Expand Down
16 changes: 14 additions & 2 deletions godot_parser/values.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
Group,
Keyword,
Opt,
ParseResults,
ParserElement,
QuotedString,
Suppress,
Word,
Expand All @@ -16,10 +18,20 @@

from .objects import GDObject

boolean = (

def parse_action_function(parse_results: ParseResults) -> bool:
result = parse_results[0]
if isinstance(result, bool):
return result
if isinstance(result, str):
return result.lower() == "true"
raise ValueError(f"Unexpected result: {result}")


boolean: ParserElement = (
(Keyword("true") | Keyword("false"))
.set_name("bool")
.set_parse_action(lambda x: x[0].lower() == "true")
.set_parse_action(parse_action_function)
)

null = Keyword("null").set_parse_action(lambda _: [None])
Expand Down
1 change: 1 addition & 0 deletions requirements_dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ tox
twine
bumpversion
build
pyparsing>=3.*
1 change: 1 addition & 0 deletions requirements_test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ black
isort
mypy
pylint==2.17.7
beartype
4 changes: 1 addition & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ platforms = any
classifiers =
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Expand All @@ -23,7 +21,7 @@ classifiers =
License :: OSI Approved :: MIT License

[options]
python_requires = >=3.6
python_requires = >=3.9
packages = find:
install_requires =
pyparsing>=3
Expand Down
15 changes: 14 additions & 1 deletion tests/test_gdfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import unittest

from godot_parser import GDFile, GDObject, GDResource, GDResourceSection, GDScene, Node
from godot_parser.sections import GDExtResourceSection, GDSubResourceSection


class TestGDFile(unittest.TestCase):
Expand Down Expand Up @@ -174,10 +175,15 @@ def test_addremove_ext_res(self):
node["texture_pool"] = GDObject("ResourcePool", res2.reference)

s = scene.find_section(path="res://Res.tscn")
assert s is not None

scene.remove_section(s)
scene.renumber_resource_ids()

s = scene.find_section("ext_resource")
assert s is not None
assert isinstance(s, GDExtResourceSection)

self.assertEqual(s.id, 1)
self.assertEqual(node["texture"], s.reference)
self.assertEqual(node["textures"][0], s.reference)
Expand All @@ -187,7 +193,7 @@ def test_addremove_ext_res(self):
def test_remove_unused_resource(self):
"""Can remove unused resources"""
scene = GDScene()
res = scene.add_ext_resource("res://Res.tscn", "PackedScene")
scene.add_ext_resource("res://Res.tscn", "PackedScene")
scene.remove_unused_resources()
resources = scene.get_sections("ext_resource")
self.assertEqual(len(resources), 0)
Expand All @@ -203,10 +209,15 @@ def test_addremove_sub_res(self):
scene.add_section(resource)

s = scene.find_sub_resource(type="CircleShape2D")
assert s is not None

scene.remove_section(s)
scene.renumber_resource_ids()

s = scene.find_section("sub_resource")
assert s is not None
assert isinstance(s, GDSubResourceSection)

self.assertEqual(s.id, 1)
self.assertEqual(resource["shape"], s.reference)

Expand Down Expand Up @@ -241,5 +252,7 @@ def test_file_equality(self):
s2 = GDScene(GDResourceSection())
self.assertEqual(s1, s2)
resource = s1.find_section("resource")
assert resource is not None

resource["key"] = "value"
self.assertNotEqual(s1, s2)
23 changes: 13 additions & 10 deletions tests/test_parser.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import os
from typing import Optional
import unittest

from pyparsing import ParseException

from beartype.door import is_bearable

from godot_parser import GDFile, GDObject, GDSection, GDSectionHeader, Vector2, parse
from godot_parser.files import GDFileType

HERE = os.path.dirname(__file__)

TEST_CASES = [

TEST_CASES: list[tuple[str, GDFileType]] = [
(
"[gd_scene load_steps=5 format=2]",
GDFile(GDSection(GDSectionHeader("gd_scene", load_steps=5, format=2))),
Expand Down Expand Up @@ -49,7 +54,7 @@
GDSectionHeader("sub_resource", type="RectangleShape2D", id=1),
extents=Vector2(12.7855, 17.0634),
other=None,
**{"with spaces": 1}
**{"with spaces": 1},
)
),
),
Expand All @@ -69,7 +74,7 @@
"update": 0,
"values": [Vector2(0, 0), Vector2(1, 0)],
}
}
},
)
),
),
Expand Down Expand Up @@ -106,28 +111,26 @@
"0:0/0": 0,
"0:0/0/physics_layer_0/linear_velocity": Vector2(0, 0),
"0:0/0/physics_layer_0/angular_velocity": 0.0,
}
},
)
),
),
]


class TestParser(unittest.TestCase):

""" """

def _run_test(self, string: str, expected):
def _run_test(self, string: str, expected: GDFileType):
"""Run a set of tests"""
parse_result: Optional[GDFileType] = None
try:
parse_result = parse(string)
if expected == "error":
assert False, "Parsing '%s' should have failed.\nGot: %s" % (
string,
parse_result,
)
else:
self.assertEqual(parse_result, expected)
condition = is_bearable(parse_result, GDFileType)
assert condition, f"Expected {type(expected)}, got {type(parse_result)}"
except ParseException as e:
if expected != "error":
print(string)
Expand Down
Loading

0 comments on commit c1af722

Please sign in to comment.