Skip to content

Commit

Permalink
Add Python 3.13 compatibility + Remove Python 3.9 (#538)
Browse files Browse the repository at this point in the history
* Add Python 3.13 / remove 3.9 support

* pyupgrade 3.10+

* Run mypy without dedicated action

* don't fail caching fast

* ci: bump Python

* bump versions

* fix mypy
  • Loading branch information
theCapypara authored Dec 20, 2024
1 parent 27aa5df commit 27d9b8a
Show file tree
Hide file tree
Showing 80 changed files with 129 additions and 131 deletions.
37 changes: 23 additions & 14 deletions .github/workflows/build-test-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ jobs:
runs-on: ubuntu-latest
name: Build Python package cache
strategy:
fail-fast: true
fail-fast: false
matrix:
python-version: [ "3.9", "3.10", "3.11", "3.12" ]
python-version: [ "3.10", "3.11", "3.12", "3.13" ]
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -85,21 +85,30 @@ jobs:
typechecks:
runs-on: ubuntu-latest
name: Type checks
needs: cache
strategy:
fail-fast: false
matrix:
python-version: [ "3.9", "3.10", "3.11", "3.12" ]
python-version: [ "3.10", "3.11", "3.12", "3.13" ]
steps:
- uses: actions/checkout@v4
with:
submodules: 'recursive'
- uses: theCapypara/mypy-check@rust-support
name: Run type checks
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
path: 'skytemple_files'
mypy_flags: '--config-file mypy.ini --junit-xml mypy-${{ matrix.python-version }}.xml'
requirements: '-r requirements.txt'
python_version: '${{ matrix.python-version }}'
python-version: ${{ matrix.python-version }}
- uses: actions/cache@v4
with:
path: ${{ env.pythonLocation }}
key: py${{ matrix.python-version }}-${{ github.run_id }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools
pip install -r requirements.txt mypy
- name: Run type checks
run: |
mypy --config-file mypy.ini --junit-xml mypy-${{ matrix.python-version }}.xml skytemple_files
- name: Upload Unit Test Results
if: always()
uses: actions/upload-artifact@v4
Expand All @@ -114,7 +123,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [ "3.9", "3.10", "3.11", "3.12" ]
python-version: [ "3.10", "3.11", "3.12", "3.13" ]
native: [true, false]
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -155,7 +164,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [ "3.9" ]
python-version: [ "3.10" ]
native: [true, false]
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -218,9 +227,9 @@ jobs:
run: |
echo "PACKAGE_VERSION=$(tomlq '.project.version' pyproject.toml -r)" >> $GITHUB_ENV
- name: Build Python wheels
uses: RalfG/[email protected]_x86_64
with:
python-versions: 'cp39-cp39 cp310-cp310 cp311-cp311 cp312-cp312'
run: |
python3 -m pip install --upgrade build
python3 -m build
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
Expand Down
10 changes: 5 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,33 @@ build-backend = "setuptools.build_meta"

[project]
name = "skytemple-files"
version = "1.8.3"
version = "1.8.4"
authors = [
{name = 'Marco "Capypara" Köpcke', email = "[email protected]"},
# see About dialog or GitHub contributors list for additional people.
]
description = "Python library to edit the ROM of Pokémon Mystery Dungeon Explorers of Sky"
readme = "README.rst"
requires-python = ">=3.9"
requires-python = ">=3.10"
keywords = ["rom-hacking", "game-modding", "skytemple"]
license = {text = "GPL-3.0-or-later"}
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python",
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
dependencies = [
"pmdsky-debug-py == 10.0.21",
"ndspy >= 3.0.0",
"range-typed-integers >= 1.0.1",
"Pillow >= 6.1.0",
"appdirs >= 1.4.0",
"explorerscript >= 0.2.1, < 0.3.0",
"skytemple-rust >= 1.8.2, < 1.9.0",
"explorerscript >= 0.2.2, < 0.3.0",
"skytemple-rust >= 1.8.4, < 1.9.0",
'pyobjc==10.3.2; sys_platform == "darwin"',
"dungeon-eos==0.0.5",
]
Expand Down
4 changes: 1 addition & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ range-typed-integers==1.0.1
Pillow==10.4.0
appdirs==1.4.4
git+https://github.com/skytemple/skytemple-rust@master#egg=skytemple_rust
explorerscript==0.2.1
explorerscript==0.2.2
dungeon-eos==0.0.5
gql[aiohttp]==3.5.0
graphql-core>=3.2.0
Expand All @@ -17,5 +17,3 @@ pytest
ruff
parameterized
xmldiff
typing_extensions >= 3.9; python_version < "3.9"
importlib_resources>=1.3; python_version < "3.9"
3 changes: 2 additions & 1 deletion skytemple_files/common/ppmdu_config/script_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
import re
import warnings
from enum import Enum, IntEnum
from typing import Iterator, Sequence, Mapping, Union
from typing import Union
from collections.abc import Iterator, Sequence, Mapping

from explorerscript.ssb_converting.ssb_data_types import SsbCoroutine, SsbOpCode
from range_typed_integers import i16, u8, u16
Expand Down
3 changes: 1 addition & 2 deletions skytemple_files/common/rw_value.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
# along with SkyTemple. If not, see <https://www.gnu.org/licenses/>.
import re
from abc import ABC, abstractmethod
from typing import Tuple

from range_typed_integers import (
i32,
Expand Down Expand Up @@ -424,7 +423,7 @@ def write_str(self, binary: bytearray, value: str, index: int = 0):
def _type_size(self) -> int:
return 2

def _get_shifted_immediate(self, value: int) -> Tuple[int, int]:
def _get_shifted_immediate(self, value: int) -> tuple[int, int]:
"""
Given an integer, attempts to encode it as a shifted immediate
:param value: Original value to encode
Expand Down
5 changes: 1 addition & 4 deletions skytemple_files/common/script_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@

from skytemple_files.list.level.model import LevelListBin

try:
from typing import TypedDict
except ImportError:
from typing_extensions import TypedDict
from typing import TypedDict

from ndspy.fnt import Folder

Expand Down
2 changes: 1 addition & 1 deletion skytemple_files/common/spritecollab/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@
from io import BytesIO
from typing import (
Any,
Callable,
Literal,
TypeVar,
cast,
overload,
)
from collections.abc import Callable
from collections.abc import Coroutine, Iterable, Sequence
from xml.etree import ElementTree
from xml.etree.ElementTree import Element
Expand Down
2 changes: 1 addition & 1 deletion skytemple_files/common/spritecollab/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,6 @@ def subscribe(
document: DocumentNode,
variable_values: dict[str, Any] | None = None,
operation_name: str | None = None,
) -> AsyncGenerator[ExecutionResult, None]:
) -> AsyncGenerator[ExecutionResult]:
# We don't cache these.
return self._transport.subscribe(document, variable_values, operation_name)
4 changes: 2 additions & 2 deletions skytemple_files/common/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@
from typing import (
TYPE_CHECKING,
Any,
Callable,
Optional,
Protocol,
TypeVar,
Union,
overload,
Literal,
)
from collections.abc import Callable
from collections.abc import Generator, Iterable, Sequence

from pmdsky_debug_py.protocol import SectionProtocol
Expand Down Expand Up @@ -711,7 +711,7 @@ def simple_quant(img: Image.Image, can_have_transparency: bool = True) -> Image.


@contextlib.contextmanager
def mutate_sequence(obj: object, attr: str) -> Generator[list[Any], None, None]:
def mutate_sequence(obj: object, attr: str) -> Generator[list[Any]]:
"""
This context manager provides the attribute sequence value behind the attribute as a list (copy),
and then assigns the attribute to that list. So while you can "mutate" the "original" sequence this way,
Expand Down
12 changes: 4 additions & 8 deletions skytemple_files/graphics/chara_wan/sheets.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,7 @@ def ImportSheets(inDir, strict=False):

if index > -1:
if index in anim_stats:
raise UserValueError(
"{} and {} both have the an index of {}!".format(anim_stats[index].name, name, index)
)
raise UserValueError(f"{anim_stats[index].name} and {name} both have the an index of {index}!")
anim_stats[index] = anim_stat

copy_indices = {}
Expand Down Expand Up @@ -210,7 +208,7 @@ def ImportSheets(inDir, strict=False):

# check against inconsistent sizing
if anim_img.size != offset_img.size or anim_img.size != shadow_img.size:
raise UserValueError("Anim, Offset, and Shadow sheets for {} must be the same size!".format(anim_name))
raise UserValueError(f"Anim, Offset, and Shadow sheets for {anim_name} must be the same size!")

if anim_img.size[0] % tileSize[0] != 0 or anim_img.size[1] % tileSize[1] != 0:
raise UserValueError(
Expand Down Expand Up @@ -299,9 +297,7 @@ def ImportSheets(inDir, strict=False):
if frame_offset[2] is None:
# raise warning if there's missing shadow or offsets
if strict:
raise UserValueError(
"No frame offset found in frame {} for {}".format((jj, dir), anim_name)
)
raise UserValueError(f"No frame offset found in frame {(jj, dir)} for {anim_name}")
offsets = FrameOffset(rel_center, rel_center, rel_center, rel_center)
else:
offsets.center = frame_offset[2]
Expand All @@ -317,7 +313,7 @@ def ImportSheets(inDir, strict=False):
if shadow_offset[4] is not None:
shadow = shadow_offset[4]
elif strict:
raise UserValueError("No shadow offset found in frame {} for {}".format((jj, dir), anim_name))
raise UserValueError(f"No shadow offset found in frame {(jj, dir)} for {anim_name}")
shadow_diff = exUtils.addLoc(shadow, rect, True)
shadow = exUtils.addLoc(shadow, rel_center, True)

Expand Down
3 changes: 1 addition & 2 deletions skytemple_files/graphics/dma/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@
#
# You should have received a copy of the GNU General Public License
# along with SkyTemple. If not, see <https://www.gnu.org/licenses/>.
from typing import Union

from skytemple_files.graphics.dma.protocol import DmaNeighbor


def get_tile_neighbors(
wall_matrix: list[list[Union[int, bool]]],
wall_matrix: list[list[int | bool]],
x,
y,
self_is_wall_or_water: bool,
Expand Down
6 changes: 3 additions & 3 deletions skytemple_files/graphics/kao/sprite_bot_sheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# along with SkyTemple. If not, see <https://www.gnu.org/licenses/>.
from __future__ import annotations

from typing import Callable
from collections.abc import Callable
from collections.abc import Generator

from PIL import Image
Expand Down Expand Up @@ -50,7 +50,7 @@ def create(cls, kao: KaoProtocol[KaoImageProtocol], portrait_item_id: int) -> Im
return image.crop((0, 0, max_x, max_y))

@classmethod
def load(cls, fn: str, portrait_name_fn: Callable[[int], str]) -> Generator[tuple[int, Image.Image], None, None]:
def load(cls, fn: str, portrait_name_fn: Callable[[int], str]) -> Generator[tuple[int, Image.Image]]:
img = Image.open(fn)
occupied = cls._verify_portraits(img, portrait_name_fn)
for xx, column in enumerate(occupied):
Expand All @@ -72,7 +72,7 @@ def load(cls, fn: str, portrait_name_fn: Callable[[int], str]) -> Generator[tupl
@classmethod
def _iter_portraits(
cls, kao: KaoProtocol[KaoImageProtocol], portrait_item_id: int
) -> Generator[tuple[KaoImageProtocol | None, KaoImageProtocol | None], None, None]:
) -> Generator[tuple[KaoImageProtocol | None, KaoImageProtocol | None]]:
for i in range(0, SUBENTRIES, 2):
yield kao.get(portrait_item_id, i), kao.get(portrait_item_id, i + 1)

Expand Down
9 changes: 4 additions & 5 deletions skytemple_files/hardcoded/symbols/binary_data_getter.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#
# You should have received a copy of the GNU General Public License
# along with SkyTemple. If not, see <https://www.gnu.org/licenses/>.
from typing import List, Dict, Optional

from pmdsky_debug_py.protocol import SectionProtocol, Symbol

Expand All @@ -27,13 +26,13 @@ class BinaryDataGetter:
"""

pmd2_data: Pmd2Data
sections_dict: Dict[str, SectionProtocol]
sections_dict: dict[str, SectionProtocol]

def __init__(self, pmd2_data: Pmd2Data):
self.pmd2_data = pmd2_data
self.sections_dict = dict(vars(pmd2_data.bin_sections))

def get_binary_names(self, starting_with: Optional[List[str]] = None) -> List[str]:
def get_binary_names(self, starting_with: list[str] | None = None) -> list[str]:
"""
Returns the names of all binaries that start with one of the specified strings, or all binaries if
starting_with is not specified.
Expand Down Expand Up @@ -76,7 +75,7 @@ def has_data_symbols(self, binary: str) -> bool:
return True
return False

def get_data_symbols(self, binary: str) -> List[Symbol]:
def get_data_symbols(self, binary: str) -> list[Symbol]:
"""
Given the name of a binary, returns the list of data symbols it contains.
This method ignores deprecated symbols.
Expand All @@ -96,7 +95,7 @@ def get_data_symbols(self, binary: str) -> List[Symbol]:

return result

def _starts_with_any(self, string: str, prefixes: List[str]) -> bool:
def _starts_with_any(self, string: str, prefixes: list[str]) -> bool:
for prefix in prefixes:
if string.startswith(prefix):
return True
Expand Down
7 changes: 3 additions & 4 deletions skytemple_files/hardcoded/symbols/c_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
# You should have received a copy of the GNU General Public License
# along with SkyTemple. If not, see <https://www.gnu.org/licenses/>.
import re
from typing import List, Optional

from skytemple_files.common.rw_value import DATA_PROCESSING_INSTRUCTION_TYPE
from skytemple_files.hardcoded.symbols.manual.equivalent_types import get_size_equivalent_type
Expand All @@ -34,9 +33,9 @@ class CType:
# String that contains the base type. Cannot be an array type.
base_type: str
# Size of each array dimension. Empty if the type is not an array type.
dim_sizes: List[int]
dim_sizes: list[int]

def __init__(self, base_type: str, dim_sizes: Optional[List[int]] = None):
def __init__(self, base_type: str, dim_sizes: list[int] | None = None):
if dim_sizes is None:
dim_sizes = []
self.base_type = base_type
Expand Down Expand Up @@ -148,7 +147,7 @@ def get_size(self) -> int:
"""
return self.get_base_type_size() * self.get_total_num_elements()

def get_multi_dimension_index(self, linear_index: int) -> List[int]:
def get_multi_dimension_index(self, linear_index: int) -> list[int]:
"""
Given a linear index between 0 and the product of all elements in self.array_size (upper bound exclusive),
returns the equivalent index for each dimension.
Expand Down
5 changes: 2 additions & 3 deletions skytemple_files/hardcoded/symbols/manual/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
# along with SkyTemple. If not, see <https://www.gnu.org/licenses/>.

# Contains information about the values of some enum types
from typing import List

from skytemple_files.hardcoded.symbols.unsupported_type_error import UnsupportedTypeError

Expand Down Expand Up @@ -239,7 +238,7 @@ def __init__(self, int_value: int, name: str):
}


def get_enum_values(type_str: str) -> List[EnumValue]:
def get_enum_values(type_str: str) -> list[EnumValue]:
"""
Given a string representing an enum type, returns its possible values
:param type_str: Enum type
Expand All @@ -258,7 +257,7 @@ def get_enum_values(type_str: str) -> List[EnumValue]:
raise ValueError("The specified type is not an enum type.")


def get_all_enum_types() -> List[str]:
def get_all_enum_types() -> list[str]:
"""
:return: List with the names of all enum types defined in this file
"""
Expand Down
Loading

0 comments on commit 27d9b8a

Please sign in to comment.