Skip to content

Commit

Permalink
More mypy annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
quantum5 committed Sep 27, 2020
1 parent 764d0f6 commit 0ecc367
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ 3.5, 3.6, 3.7, 3.8 ]
python-version: [ 3.6, 3.7, 3.8, 3.9.0-alpha - 3.9 ]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
Expand Down
2 changes: 1 addition & 1 deletion win2xcur/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def main() -> None:

check_xcursorgen()

def process(file):
def process(file) -> None:
name = file.name
blob = file.read()
try:
Expand Down
7 changes: 5 additions & 2 deletions win2xcur/parser/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from typing import List, Type

from win2xcur.parser.ani import ANIParser
from win2xcur.parser.base import BaseParser
from win2xcur.parser.cur import CURParser

PARSERS = [CURParser, ANIParser]
PARSERS: List[Type[BaseParser]] = [CURParser, ANIParser]


def open_blob(blob):
def open_blob(blob: bytes) -> BaseParser:
for parser in PARSERS:
if parser.can_parse(blob):
return parser(blob)
Expand Down
17 changes: 10 additions & 7 deletions win2xcur/parser/ani.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import struct
from copy import copy
from typing import Any, Iterable, List, Tuple

from win2xcur.cursor import CursorFrame
from win2xcur.parser.base import BaseParser
from win2xcur.parser.cur import CURParser


class ANIParser:
class ANIParser(BaseParser):
SIGNATURE = b'RIFF'
ANI_TYPE = b'ACON'
FRAME_TYPE = b'fram'
Expand All @@ -16,26 +19,26 @@ class ANIParser:
ICON_FLAG = 0x1

@classmethod
def can_parse(cls, blob):
def can_parse(cls, blob: bytes) -> bool:
signature, size, subtype = cls.RIFF_HEADER.unpack(blob[:cls.RIFF_HEADER.size])
return signature == cls.SIGNATURE and size == len(blob) - 8 and subtype == cls.ANI_TYPE

def __init__(self, blob):
self.blob = blob
def __init__(self, blob: bytes) -> None:
super().__init__(blob)
if not self.can_parse(blob):
raise ValueError('Not a .ani file')
self.frames = self._parse(self.RIFF_HEADER.size)

def _unpack(self, struct_cls, offset):
def _unpack(self, struct_cls: struct.Struct, offset: int) -> Tuple[Any, ...]:
return struct_cls.unpack(self.blob[offset:offset + struct_cls.size])

def _read_chunk(self, offset, expected):
def _read_chunk(self, offset: int, expected: Iterable[bytes]) -> Tuple[int, int]:
name, size = self._unpack(self.CHUNK_HEADER, offset)
if name not in expected:
raise ValueError('Expected chunk %r, found %r' % (expected, name))
return size, offset + self.CHUNK_HEADER.size

def _parse(self, offset):
def _parse(self, offset: int) -> List[CursorFrame]:
size, offset = self._read_chunk(offset, expected=[b'anih'])

if size != self.ANIH_HEADER.size:
Expand Down
18 changes: 18 additions & 0 deletions win2xcur/parser/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from abc import ABCMeta, abstractmethod
from typing import List

from win2xcur.cursor import CursorFrame


class BaseParser(metaclass=ABCMeta):
blob: bytes
frames: List[CursorFrame]

@abstractmethod
def __init__(self, blob: bytes) -> None:
self.blob = blob

@classmethod
@abstractmethod
def can_parse(cls, blob: bytes) -> bool:
raise NotImplementedError()
12 changes: 7 additions & 5 deletions win2xcur/parser/cur.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
import struct
from typing import List, Tuple

from wand.image import Image

from win2xcur.cursor import CursorFrame, CursorImage
from win2xcur.parser.base import BaseParser


class CURParser:
class CURParser(BaseParser):
MAGIC = b'\0\0\02\0'
ICON_DIR = struct.Struct('<HHH')
ICON_DIR_ENTRY = struct.Struct('<BBBBHHII')

@classmethod
def can_parse(cls, blob):
def can_parse(cls, blob: bytes) -> bool:
return blob[:len(cls.MAGIC)] == cls.MAGIC

def __init__(self, blob):
self.blob = blob
def __init__(self, blob: bytes) -> None:
super().__init__(blob)
self._image = Image(blob=blob, format='cur')
self._hotspots = self._parse_header()
self.frames = [CursorFrame([
CursorImage(image, hotspot) for image, hotspot in zip(self._image.sequence, self._hotspots)
])]

def _parse_header(self):
def _parse_header(self) -> List[Tuple[int, int]]:
reserved, ico_type, image_count = self.ICON_DIR.unpack(self.blob[:self.ICON_DIR.size])
assert reserved == 0
assert ico_type == 2
Expand Down
2 changes: 1 addition & 1 deletion win2xcur/shadow.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def apply_to_image(image: BaseImage, *, color: str, radius: float, sigma: float,
return result


def apply_to_frames(frames: List[CursorFrame], **kwargs):
def apply_to_frames(frames: List[CursorFrame], **kwargs) -> None:
for frame in frames:
for cursor in frame:
cursor.image = apply_to_image(cursor.image, **kwargs)

0 comments on commit 0ecc367

Please sign in to comment.