Skip to content

Commit

Permalink
Improve typing in pystow.utils (#80)
Browse files Browse the repository at this point in the history
This PR does the following:

1. Adds a literal for typing the download backend
2. Modernizes the use of type stubs for type annotating hashes
3. Switches to `typing.NamedTuple` for hexdigest mismatches
  • Loading branch information
cthoyt authored Nov 16, 2024
1 parent 5be6357 commit 7c37661
Showing 1 changed file with 28 additions and 7 deletions.
35 changes: 28 additions & 7 deletions src/pystow/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

"""Utilities."""

from __future__ import annotations

import contextlib
import gzip
import hashlib
Expand All @@ -14,7 +16,6 @@
import tempfile
import urllib.error
import zipfile
from collections import namedtuple
from functools import partial
from io import BytesIO, StringIO
from pathlib import Path, PurePosixPath
Expand All @@ -25,7 +26,9 @@
Collection,
Iterable,
Iterator,
Literal,
Mapping,
NamedTuple,
Optional,
Union,
)
Expand All @@ -35,6 +38,7 @@

import requests
from tqdm.auto import tqdm
from typing_extensions import TypeAlias

from .constants import (
PYSTOW_HOME_ENVVAR,
Expand All @@ -52,8 +56,10 @@
import rdflib

__all__ = [
# Data Structures
# Data Structures and type annotations
"HexDigestMismatch",
"DownloadBackend",
"Hash",
# Exceptions
"HexDigestError",
"UnexpectedDirectory",
Expand Down Expand Up @@ -105,10 +111,25 @@

logger = logging.getLogger(__name__)

# Since we're python 3.6 compatible, we can't do from __future__ import annotations and use hashlib._Hash
Hash = Any

HexDigestMismatch = namedtuple("HexDigestMismatch", "name actual expected")
#: Represents an available backend for downloading
DownloadBackend: TypeAlias = Literal["urllib", "requests"]

#: This type alias uses a stub-only constructor, meaning that
#: hashlib._Hash isn't actually part of the code, but MyPy injects it
#: so we can do type checking
Hash: TypeAlias = "hashlib._Hash"


class HexDigestMismatch(NamedTuple):
"""Contains information about a hexdigest mismatch."""

#: the name of the algorithm
name: str
#: the observed/actual hexdigest, encoded as a string
actual: str
#: the expected hexdigest, encoded as a string
expected: str


class HexDigestError(ValueError):
Expand Down Expand Up @@ -311,7 +332,7 @@ def download(
path: Union[str, Path],
force: bool = True,
clean_on_failure: bool = True,
backend: str = "urllib",
backend: DownloadBackend = "urllib",
hexdigests: Optional[Mapping[str, str]] = None,
hexdigests_remote: Optional[Mapping[str, str]] = None,
hexdigests_strict: bool = False,
Expand Down Expand Up @@ -421,7 +442,7 @@ def download(
class DownloadError(OSError):
"""An error that wraps information from a requests or urllib download failure."""

def __init__(self, backend: str, url: str, path: Path) -> None:
def __init__(self, backend: DownloadBackend, url: str, path: Path) -> None:
"""Initialize the error.
:param backend: The backend used
Expand Down

0 comments on commit 7c37661

Please sign in to comment.