Skip to content

Commit

Permalink
Ruff, some annotations, and some environment tweaking.
Browse files Browse the repository at this point in the history
  • Loading branch information
Julian committed Jun 11, 2023
1 parent 6e3104f commit da481c2
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 47 deletions.
7 changes: 6 additions & 1 deletion avif/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
from avif._api import AVIFError, Decoder # noqa: F401
"""
Python bindings for libavif.
"""
from avif._api import AVIFError, Decoder

__all__ = ["AVIFError", "Decoder"]
10 changes: 4 additions & 6 deletions avif/_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ class AVIFError(Exception):
pass


def _succeed(avif_result):
def _succeed(avif_result: int):
"""
Raise an exception if a ``libavif`` library function failed.
"""

if avif_result != lib.AVIF_RESULT_OK:
c_string = lib.avifResultToString(avif_result)
raise AVIFError(ffi.string(c_string).decode("utf-8"))
Expand All @@ -23,7 +22,6 @@ def _avifDecoder():
"""
Create an FFI-managed avifDecoder.
"""

return ffi.gc(lib.avifDecoderCreate(), lib.avifDecoderDestroy)


Expand All @@ -35,12 +33,12 @@ class Decoder:

_decoder = attr.ib(factory=_avifDecoder)

def parse_path(self, path):
def parse_path(self, path: str):
_succeed(lib.avifDecoderSetIOFile(self._decoder, os.fsencode(path)))
_succeed(lib.avifDecoderParse(self._decoder))
return self._decoder.image

def parse_data(self, data):
def parse_data(self, data: bytes):
_succeed(lib.avifDecoderSetIOMemory(self._decoder, data, len(data)))
_succeed(lib.avifDecoderParse(self._decoder))
return self._decoder.image
Expand All @@ -53,7 +51,7 @@ def next_images(self):
_succeed(res)
yield self._decoder.image

def nth_image(self, n):
def nth_image(self, n: int):
_succeed(lib.avifDecoderNthImage(self._decoder, n))

return self._decoder.image
21 changes: 17 additions & 4 deletions avif/pillow/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
"""
Pillow plugin for decoding animated and static avif files. (only 8bit)
Pillow plugin for decoding animated and static avif files.
Only 8-bit files are currently supported.
Based on:
https://github.com/python-pillow/Pillow/blob/master/src/PIL/WebPImagePlugin.py
"""
Expand All @@ -12,13 +15,17 @@
from avif import Decoder


def _accept(data):
def _accept(data: bytes):
possible_ftyp = (b"avif", b"avis", b"mif1")

return data[4:8] == b"ftyp" and data[8:12] in possible_ftyp


class AvifImageFile(ImageFile.ImageFile):
"""
A Pillow ImageFile for AVIF.
"""

format = "AVIF"
format_description = "Image container for AV1 video frames"

Expand All @@ -43,7 +50,10 @@ def _open(self):
self.rawmode = self.mode
self.tile = []

def seek(self, n):
def seek(self, n: int) -> None:
"""
Seek!
"""
self._seek_to_frame = n

def _get_frame(self):
Expand All @@ -62,7 +72,10 @@ def _get_frame(self):

return data

def load(self):
def load(self) -> Image.PixelAccess:
"""
Load!
"""
if self._current_frame != self._seek_to_frame:
self._current_frame = self._seek_to_frame

Expand Down
5 changes: 1 addition & 4 deletions avif/tests/test_avif.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
def test_it_imports():
import _avif

_avif

from avif import Decoder
import _avif # noqa: F401

Decoder()
2 changes: 1 addition & 1 deletion examples/avif_example_decode_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from avif import Decoder


def main():
def main() -> None:
filename = sys.argv[1]

rgb = ffi.new("avifRGBImage*")
Expand Down
2 changes: 1 addition & 1 deletion examples/avif_example_pillow_decode_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import avif.pillow # noqa: F401


def main():
def main() -> None:
filename = sys.argv[1]

image = Image.open(filename)
Expand Down
67 changes: 37 additions & 30 deletions noxfile.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from pathlib import Path
from tempfile import TemporaryDirectory
import os

import nox

Expand All @@ -21,42 +23,47 @@ def _session(fn):

@session(python=["3.8", "3.9", "3.10", "3.11", "pypy3"])
def tests(session):
session.install(str(ROOT), "pytest")
session.run("pytest")
session.install(ROOT, "pytest")

if session.posargs and session.posargs[0] == "coverage":
if len(session.posargs) > 1 and session.posargs[1] == "github":
github = os.environ["GITHUB_STEP_SUMMARY"]
else:
github = None

@session(tags=["build"])
def build(session):
session.install("build")
tmpdir = session.create_tmp()
session.run("python", "-m", "build", str(ROOT), "--outdir", tmpdir)
session.install("coverage[toml]")
session.run("coverage", "run", "-m", "pytest", AVIF)
if github is None:
session.run("coverage", "report")
else:
with open(github, "a") as summary:
summary.write("### Coverage\n\n")
summary.flush() # without a flush, output seems out of order.
session.run(
"coverage",
"report",
"--format=markdown",
stdout=summary,
)
else:
session.run("pytest", *session.posargs, AVIF)


@session(tags=["style"])
def readme(session):
@session()
def audit(session):
session.install("pip-audit", ROOT)
session.run("python", "-m", "pip_audit")


@session(tags=["build"])
def build(session):
session.install("build", "twine")
tmpdir = session.create_tmp()
session.run("python", "-m", "build", str(ROOT), "--outdir", tmpdir)
session.run("python", "-m", "twine", "check", tmpdir + "/*")
with TemporaryDirectory() as tmpdir:
session.run("python", "-m", "build", ROOT, "--outdir", tmpdir)
session.run("twine", "check", "--strict", tmpdir + "/*")


@session(tags=["style"])
def style(session):
session.install(
"flake8",
"flake8-broken-line",
"flake8-bugbear",
"flake8-commas",
"flake8-quotes",
"flake8-tidy-imports",
)
session.run(
"python",
"-m",
"flake8",
"--config",
str(ROOT / ".flake8"),
str(EXAMPLES),
str(AVIF),
__file__,
)
session.install("ruff")
session.run("ruff", "check", ROOT)
67 changes: 67 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,77 @@ requires = [
]
build-backend = "setuptools.build_meta"

[tool.coverage.html]
show_contexts = true
skip_covered = false

[tool.coverage.run]
branch = true
source = ["referencing"]
dynamic_context = "test_function"

[tool.coverage.report]
exclude_also = [
"if TYPE_CHECKING:",
"\\s*\\.\\.\\.\\s*",
]
show_missing = true
skip_covered = true

[tool.doc8]
ignore = [
"D001", # one sentence per line, so max length doesn't make sense
]

[tool.isort]
combine_as_imports = true
from_first = true
include_trailing_comma = true
known_first_party = "_avif"
multi_line_output = 3

[tool.setuptools_scm]

[tool.ruff]
line-length = 79
target-version = "py38"
select = ["ANN", "B", "D", "E", "F", "Q", "UP", "W"]
ignore = [
# Wat, type annotations for self and cls, why is this a thing?
"ANN101",
"ANN102",
# Private annotations are fine to leave out.
"ANN202",
# I don't know how to more properly annotate "pass along all arguments".
"ANN401",
# raise SomeException(...) is fine.
"B904",
# It's fine to not have docstrings for magic methods.
"D105",
# This rule makes diffs uglier when expanding docstrings (and it's uglier)
"D200",
# No blank lines before docstrings.
"D203",
# Start docstrings on the second line.
"D212",
# This rule misses sassy docstrings ending with ! or ?.
"D400",
# Section headers should end with a colon not a newline
"D406",
# Underlines aren't needed
"D407",
# Plz spaces after section headers
"D412",
# We support 3.8 + 3.9
"UP007",
]

[tool.ruff.flake8-quotes]
docstring-quotes = "double"

[tool.ruff.per-file-ignores]
"docs/*" = ["ANN", "D"]
"examples*" = ["D103"]
"avif/tests/*" = ["ANN", "D"]
"noxfile.py" = ["ANN", "D"]
"setup.py" = ["ANN", "D"]

0 comments on commit da481c2

Please sign in to comment.