Skip to content

Commit

Permalink
docs: update docstrings (#176)
Browse files Browse the repository at this point in the history
* docs: update docstrings
* fix: type hints
* chore: add `pyright` config
  • Loading branch information
DeadNews authored Feb 20, 2024
1 parent 15678ee commit 1f5b20d
Show file tree
Hide file tree
Showing 15 changed files with 235 additions and 307 deletions.
1 change: 1 addition & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"recommendations": [
"charliermarsh.ruff",
"ms-pyright.pyright",
"ms-python.mypy-type-checker",
"ms-python.python",
"tamasfe.even-better-toml"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Options:
-n, --notify Send desktop notification on completion. Required libnotify.
-c, --clipboard / -C, --no-clipboard
Copy the result to the clipboard. Enabled by default.
--env-file FILE The path to the environment file. Take precedence over the default config file.
--env-file FILE The path to the environment file. Takes precedence over the default config file.
--log-level [DEBUG|INFO|WARNING|ERROR|CRITICAL]
Use DEBUG to show debug logs. Use CRITICAL to suppress all logs. [default: INFO]
--version Show the version and exit.
Expand Down
20 changes: 10 additions & 10 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 8 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ rich = "^13.7.0"
[tool.poetry.group.lint.dependencies]
mypy = "^1.8.0"
poethepoet = "^0.24.4"
pyright = "^1.1.350"
pyright = "^1.1.351"
ruff = "^0.2.2"

[tool.poetry.group.test.dependencies]
Expand All @@ -40,7 +40,7 @@ pytest-benchmark = "^4.0.0"
pytest-cov = "^4.1.0"
pytest-httpx = "^0.29.0"
pytest-mock = "^3.12.0"
logot = "^1.1.0"
logot = "^1.1.1"

[tool.poetry.group.build.dependencies]
nuitka = "^2.0.3"
Expand All @@ -52,7 +52,7 @@ style = "semver"

[tool.poe.tasks]
mypy = "mypy ."
pyright = "pyright src"
pyright = "pyright ."
ruff = "ruff check ."
ruff-fmt = "ruff format ."
lint.sequence = ["ruff", "ruff-fmt", "mypy"]
Expand Down Expand Up @@ -98,6 +98,11 @@ warn_unused_ignores = true
module = ["tests.*"]
disallow_untyped_defs = false

[tool.pyright]
include = ["src"]
ignore = ["tests"]
typeCheckingMode = "standard"

[tool.ruff]
line-length = 99
target-version = "py310" # Until Poetry v2
Expand All @@ -109,14 +114,10 @@ line-ending = "lf"
select = ["ALL"]
ignore = [
"COM812", # Trailing comma missing
"D203", # 1 blank line required before class docstring
"D212", # Multi-line docstring summary should start at the first line
"FBT001", # Boolean positional arg in function definition
"FBT002", # Boolean default value in function definition
"ISC001", # Checks for implicitly concatenated strings on a single line
"PLR0913", # Too many arguments to function call
#
"S603", # Calling subprocess.Popen with shell=False
]

[tool.ruff.lint.per-file-ignores]
Expand Down
31 changes: 16 additions & 15 deletions src/images_upload_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
@click.option(
"--env-file",
type=click.Path(exists=True, dir_okay=False, path_type=Path),
help="The path to the environment file. Take precedence over the default config file.",
help="The path to the environment file. Takes precedence over the default config file.",
)
@click.option(
"--log-level",
Expand All @@ -72,21 +72,22 @@ def cli(
env_file: Path,
log_level: str,
) -> None:
"""Upload images via APIs."""
"""
Args:
images (tuple[Path]): A tuple of `Path` objects representing the paths to the images to upload.
hosting (str): The hosting service to use for uploading the images.
fmt (str): The format to use for generating the links to the uploaded images.
thumbnail (bool): A boolean flag indicating whether thumbnail images should be generated for the uploaded images.
notify (bool): A boolean flag indicating whether to send desktop notification on completion.
clipboard (bool): A boolean flag indicating whether to copy the image links to the clipboard.
env_file (Path): The path to the environment file.
log_level (str): The log level to use for the logger.
"""Upload images via APIs.
\f
Upload images to the specified hosting service, format links, and print.
Optionally copy links to clipboard and send desktop notification.
Returns:
None. Prints the links to the uploaded images, optionally copies them to the clipboard, and sends desktop notification.
"""
Args:
images: The paths to the images to upload.
hosting: The hosting service to use for uploading the images.
fmt: The format to use for generating the links to the uploaded images.
thumbnail: Whether thumbnail images should be generated for the uploaded images.
notify: Whether to send desktop notification on completion.
clipboard: Whether to copy the image links to the clipboard.
env_file: The path to the environment file.
log_level: The log level to use for the logger.
""" # noqa: D301
# Set up logger.
error_handler = setup_logger(log_level=log_level)
# Load environment variables.
Expand Down
34 changes: 15 additions & 19 deletions src/images_upload_cli/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,27 @@


def get_img_ext(img: bytes) -> str:
"""
Get the extension of an image from a byte string.
"""Get the extension of an image from a byte string.
Args:
img (bytes): A byte string representing an image.
img: A byte string representing an image.
Returns:
str: The extension of the image file.
The extension of the image file.
"""
with BytesIO(img) as f:
ext = Image.open(f).format
return "" if ext is None else ext.lower()


def get_font(size: int = 14) -> ImageFont.FreeTypeFont:
"""
Get font for thumbnail captions.
"""Get font for thumbnail captions.
Args:
size: An integer representing the size of the font. Defaults to 14 if not provided.
size: The size of the font. Defaults to 14.
Returns:
An instance of the `ImageFont.FreeTypeFont` class representing the font for captions.
ImageFont.FreeTypeFont: Represents the font.
"""
if font_name := getenv("CAPTION_FONT"):
return ImageFont.truetype(font_name, size=size)
Expand All @@ -47,15 +45,14 @@ def get_font(size: int = 14) -> ImageFont.FreeTypeFont:


def search_font(fonts: list[str], size: int = 14) -> ImageFont.FreeTypeFont:
"""
Attempt to retrieve a TTF font from the system.
"""Attempt to retrieve a TTF font from the system.
Args:
fonts (list[str]): A list of font names to search for.
size (int, optional): An integer representing the size of the font. Defaults to 14 if not provided.
fonts: A list of font names to search for.
size: The font size. Defaults to 14.
Returns:
An instance of the `ImageFont.FreeTypeFont` class representing the default font, if found.
ImageFont.FreeTypeFont: Represents the font.
Raises:
GetEnvError: If none of the default fonts are found.
Expand All @@ -78,16 +75,15 @@ def make_thumbnail(
font: ImageFont.FreeTypeFont,
size: tuple[int, int] = (300, 300),
) -> bytes:
"""
Generate thumbnail for the image.
"""Generate thumbnail for the image.
Args:
img (bytes): The input image in bytes format.
font (ImageFont.FreeTypeFont): The font to be used for the text caption.
size (tuple[int, int], optional): The desired size of the thumbnail image.
img: The input image in bytes format.
font: The font to be used for the text caption.
size: The desired size of the thumbnail image. Defaults to (300, 300).
Returns:
bytes: The modified image in bytes format.
The modified image in bytes format.
"""
# Open the input image and create a copy in RGB format.
im = Image.open(BytesIO(img))
Expand Down
5 changes: 2 additions & 3 deletions src/images_upload_cli/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ def has_error_occurred(self: "ErrorHandler") -> bool:


def setup_logger(log_level: str) -> ErrorHandler:
"""
Configure logger.
"""Configure logger.
Args:
log_level (str): The log level to set for the logger.
log_level: The log level to set for the logger.
Returns:
ErrorHandler: The error handler associated with the logger.
Expand Down
35 changes: 16 additions & 19 deletions src/images_upload_cli/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Main logic for the images-upload-cli package."""

from collections.abc import Callable
from collections.abc import Awaitable, Callable, Sequence
from pathlib import Path

from httpx import AsyncClient
Expand All @@ -9,22 +9,20 @@


async def upload_images(
upload_func: Callable,
upload_func: Callable[[AsyncClient, bytes], Awaitable[str]],
images: tuple[Path],
thumbnail: bool,
) -> list[tuple[str, str | None]]:
"""
Uploads images using the specified upload function.
) -> Sequence[tuple[str, str] | tuple[str, None]]:
"""Upload images using the specified upload function and optionally generate thumbnails.
Args:
upload_func (Callable): The function used to upload the images.
images (tuple[Path]): The paths of the images to be uploaded.
thumbnail (bool): Indicates whether to generate thumbnails for the images.
upload_func: The function used to upload the images.
images: The paths of the images to be uploaded.
thumbnail: Indicates whether to generate thumbnails for the images.
Returns:
list[tuple[str, str | None]]: A list of tuples containing the links to the uploaded images
and their corresponding thumbnails (if generated). The thumbnail link will be None if
thumbnails are not generated.
The links to the uploaded images and their corresponding thumbnails.
The thumbnail link will be `None` if generation is disabled.
"""
links = []

Expand All @@ -35,14 +33,14 @@ async def upload_images(
for img_path in images:
img = img_path.read_bytes()

img_link = await upload_func(client, img=img)
img_link = await upload_func(client, img)
# If the upload fails, skip the current image and proceed with the next one.
if not img_link:
continue

if thumbnail:
thumb = make_thumbnail(img, font) # pyright: ignore[reportPossiblyUnboundVariable]
thumb_link = await upload_func(client, img=thumb)
thumb_link = await upload_func(client, thumb)
# If the upload fails, skip the current image and proceed with the next one.
if not thumb_link:
continue
Expand All @@ -54,16 +52,15 @@ async def upload_images(
return links


def format_link(links: list[tuple[str, str | None]], fmt: str) -> str:
"""
Format the image links based on the specified format.
def format_link(links: Sequence[tuple[str, str] | tuple[str, None]], fmt: str) -> str:
"""Format the image links based on the specified format.
Args:
links (list[tuple[str, str | None]]): A list of tuples containing image links and optional thumbnail links.
fmt (str): The desired format for the image links. Valid options are "plain", "bbcode", "html", and "markdown".
links: The image links and their corresponding thumbnails.
fmt: The format to use for formatting the links. Valid options are "plain", "bbcode", "html", and "markdown".
Returns:
str: The formatted image links.
The formatted image links as a string.
"""
if fmt == "plain":
return " ".join([img_link for img_link, _ in links])
Expand Down
Loading

0 comments on commit 1f5b20d

Please sign in to comment.