Skip to content

Commit

Permalink
Use __future__.annotations instead of stringified type annotations
Browse files Browse the repository at this point in the history
`from __future__ import annotations` became available in Python 3.7, so
there is no reason for us not to use it instead of the older
"stringified" type annotations (for types that are not yet declared at
the time the parser encounters the annotation).
  • Loading branch information
jherland committed Jan 19, 2024
1 parent a4c9327 commit e9a59a9
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 14 deletions.
4 changes: 3 additions & 1 deletion fawltydeps/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
arguments.
"""

from __future__ import annotations

import json
import logging
import sys
Expand Down Expand Up @@ -168,7 +170,7 @@ def unused_deps(self) -> List[UnusedDependency]:
)

@classmethod
def create(cls, settings: Settings, stdin: Optional[BinaryIO] = None) -> "Analysis":
def create(cls, settings: Settings, stdin: Optional[BinaryIO] = None) -> Analysis:
"""Exercise FawltyDeps' core logic according to the given settings.
Perform the actions specified in 'settings.actions' and apply the other
Expand Down
8 changes: 5 additions & 3 deletions fawltydeps/settings.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""FawltyDeps configuration and command-line options."""
from __future__ import annotations

import argparse
import json
import logging
Expand Down Expand Up @@ -61,7 +63,7 @@ class OrderedEnum(Enum):
def __lt__(self, other: object) -> bool:
if not isinstance(other, OrderedEnum):
return NotImplemented
values: List["OrderedEnum"] = list(self.__class__)
values: List[OrderedEnum] = list(self.__class__)
return values.index(self) < values.index(other)


Expand Down Expand Up @@ -205,7 +207,7 @@ def customise_sources(
)

@classmethod
def config(cls, **kwargs: Union[None, Path, str]) -> Type["Settings"]:
def config(cls, **kwargs: Union[None, Path, str]) -> Type[Settings]:
"""Configure the class variables in this Settings class.
This must be done _before_ instantiating Settings objects, as the
Expand All @@ -218,7 +220,7 @@ class variables affect how this instantiation is done (e.g. which
return cls

@classmethod
def create(cls, cmdline_args: argparse.Namespace) -> "Settings":
def create(cls, cmdline_args: argparse.Namespace) -> Settings:
"""Convert the parsed command-line args into a Settings object.
Extract the relevant parts of the given argparse.Namespace object into
Expand Down
6 changes: 4 additions & 2 deletions fawltydeps/types.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Common types used across FawltyDeps."""

from __future__ import annotations

import sys
from abc import ABC, abstractmethod
from dataclasses import asdict, dataclass, field, replace
Expand Down Expand Up @@ -54,7 +56,7 @@ class Source(ABC):
This exists to inject the class name of the subclass into our JSON output.
"""

source_type: Type["Source"] = field(init=False)
source_type: Type[Source] = field(init=False)

def __post_init__(self) -> None:
object.__setattr__(self, "source_type", self.__class__)
Expand Down Expand Up @@ -248,7 +250,7 @@ def __str__(self) -> str:
ret += f":{self.lineno}"
return ret

def supply(self, **changes: int) -> "Location":
def supply(self, **changes: int) -> Location:
"""Create a new Location that contains additional information."""
return replace(self, **changes)

Expand Down
10 changes: 6 additions & 4 deletions tests/project_helpers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""Common helpers shared between test_real_project and test_sample_projects."""
from __future__ import annotations

import hashlib
import logging
import os
Expand Down Expand Up @@ -48,7 +50,7 @@ class TarballPackage:
filename_must_include: Optional[str] = None

@classmethod
def collect_from_toml(cls, path: Path) -> Iterator["TarballPackage"]:
def collect_from_toml(cls, path: Path) -> Iterator[TarballPackage]:
"""Parse information on all available tarball packages in a toml file."""
tarballs = parse_toml(path)
for info in tarballs.values():
Expand Down Expand Up @@ -226,7 +228,7 @@ class AnalysisExpectations:
unused_deps: Optional[Set[str]] = None

@classmethod
def from_toml(cls, data: TomlData) -> "AnalysisExpectations":
def from_toml(cls, data: TomlData) -> AnalysisExpectations:
"""Read expectations from the given TOML table."""

def set_or_none(data: Optional[Iterable[str]]) -> Optional[Set[str]]:
Expand Down Expand Up @@ -292,7 +294,7 @@ def _init_args_from_toml(name: str, data: TomlData) -> Dict[str, Any]:

@classmethod
@abstractmethod
def from_toml(cls, name: str, data: TomlData) -> "BaseExperiment":
def from_toml(cls, name: str, data: TomlData) -> BaseExperiment:
"""Create an instance from TOML data."""
raise NotImplementedError

Expand Down Expand Up @@ -336,7 +338,7 @@ def _init_args_from_toml(

@classmethod
@abstractmethod
def collect(cls) -> Iterator["BaseProject"]:
def collect(cls) -> Iterator[BaseProject]:
"""Find and generate all projects in this test suite."""
raise NotImplementedError

Expand Down
6 changes: 4 additions & 2 deletions tests/test_real_projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
FawltyDeps on them, with hardcoded expectations per project on what FawltyDeps
should find/report.
"""
from __future__ import annotations

import json
import logging
import subprocess
Expand Down Expand Up @@ -77,7 +79,7 @@ class Experiment(BaseExperiment):
args: List[str]

@classmethod
def from_toml(cls, name: str, data: TomlData) -> "Experiment":
def from_toml(cls, name: str, data: TomlData) -> Experiment:
return cls(args=data["args"], **cls._init_args_from_toml(name, data))


Expand All @@ -98,7 +100,7 @@ class ThirdPartyProject(BaseProject):
tarball: TarballPackage

@classmethod
def collect(cls) -> Iterator["ThirdPartyProject"]:
def collect(cls) -> Iterator[ThirdPartyProject]:
for path in filter(lambda p: p.suffix == ".toml", REAL_PROJECTS_DIR.iterdir()):
toml_data = parse_toml(path)
project_info = cls._init_args_from_toml(toml_data, Experiment)
Expand Down
6 changes: 4 additions & 2 deletions tests/test_sample_projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
├── expected.toml (mandatory)
└── ... (regular Python project)
"""
from __future__ import annotations

import sys
from dataclasses import dataclass
from pathlib import Path
Expand Down Expand Up @@ -62,7 +64,7 @@ class Experiment(BaseExperiment):
exclude: List[str]

@classmethod
def from_toml(cls, name: str, data: TomlData) -> "Experiment":
def from_toml(cls, name: str, data: TomlData) -> Experiment:
return cls(
code=data.get("code", [""]),
deps=data.get("deps", [""]),
Expand Down Expand Up @@ -103,7 +105,7 @@ class SampleProject(BaseProject):
path: Path # Directory containing expected.toml, and rest of sample project

@classmethod
def collect(cls) -> Iterator["SampleProject"]:
def collect(cls) -> Iterator[SampleProject]:
for subdir in SAMPLE_PROJECTS_DIR.iterdir():
toml_path = subdir / "expected.toml"
if not toml_path.is_file():
Expand Down

0 comments on commit e9a59a9

Please sign in to comment.