diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 07eeaac..2e6aa1d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: check-yaml @@ -10,7 +10,7 @@ repos: - id: isort - repo: https://github.com/psf/black - rev: 24.8.0 + rev: 24.10.0 hooks: - id: black name: black @@ -19,9 +19,10 @@ repos: rev: 7.1.1 hooks: - id: flake8 + additional_dependencies: [flake8-breakpoint, flake8-print, flake8-pydantic, flake8-type-checking] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.2 + rev: v1.13.0 hooks: - id: mypy additional_dependencies: [types-requests, types-setuptools, pydantic] diff --git a/ethpm_types/abi.py b/ethpm_types/abi.py index 8c377fd..04c40ab 100644 --- a/ethpm_types/abi.py +++ b/ethpm_types/abi.py @@ -1,11 +1,13 @@ -from typing import Literal, Optional, Union +from typing import TYPE_CHECKING, Literal, Optional, Union from pydantic import ConfigDict, Field -from typing_extensions import Self from ethpm_types.base import BaseModel from ethpm_types.utils import parse_signature +if TYPE_CHECKING: + from typing_extensions import Self + class ABIType(BaseModel): name: Optional[str] = None @@ -280,7 +282,7 @@ def signature(self) -> str: return f"{self.name}({input_args}){output_args}" @classmethod - def from_signature(cls, sig: str) -> Self: + def from_signature(cls, sig: str) -> "Self": """ Create an MethodABI instance from a method signature. @@ -332,7 +334,7 @@ def signature(self) -> str: return f"{self.name}({input_args})" @classmethod - def from_signature(cls, sig: str) -> Self: + def from_signature(cls, sig: str) -> "Self": """Create an EventABI instance from an event signature.""" name, inputs, _ = parse_signature(sig) input_abis = [ diff --git a/ethpm_types/ast.py b/ethpm_types/ast.py index 49a0cc5..d1a0a3b 100644 --- a/ethpm_types/ast.py +++ b/ethpm_types/ast.py @@ -118,7 +118,7 @@ def add_child(data): return children @property - def line_numbers(self) -> SourceLocation: + def line_numbers(self) -> "SourceLocation": """ The values needed for constructing the line numbers for this node in the form ``[lineno, col_offset, end_lineno, end_col_offset]``. @@ -174,7 +174,7 @@ def get_node(self, src: SourceMapItem) -> Optional["ASTNode"]: return None - def get_nodes_at_line(self, line_numbers: SourceLocation) -> list["ASTNode"]: + def get_nodes_at_line(self, line_numbers: "SourceLocation") -> list["ASTNode"]: """ Get the AST nodes for the given line number combination @@ -202,7 +202,7 @@ def get_nodes_at_line(self, line_numbers: SourceLocation) -> list["ASTNode"]: return nodes - def get_defining_function(self, line_numbers: SourceLocation) -> Optional["ASTNode"]: + def get_defining_function(self, line_numbers: "SourceLocation") -> Optional["ASTNode"]: """ Get the function that defines the given line numbers. @@ -220,3 +220,10 @@ def get_defining_function(self, line_numbers: SourceLocation) -> Optional["ASTNo return function return None + + +__all__ = [ + "ASTClassification", + "ASTNode", + "SourceLocation", # For backwards compat. +] diff --git a/ethpm_types/manifest.py b/ethpm_types/manifest.py index dd73f2a..d1bf436 100644 --- a/ethpm_types/manifest.py +++ b/ethpm_types/manifest.py @@ -2,13 +2,14 @@ from typing import Optional from eth_pydantic_types import Bip122Uri -from pydantic import AnyUrl, Field, field_validator, model_validator +from pydantic import Field, field_validator, model_validator from pydantic_core import CoreSchema, PydanticCustomError from pydantic_core.core_schema import str_schema, with_info_before_validator_function from ethpm_types.base import BaseModel from ethpm_types.contract_type import ContractInstance, ContractType from ethpm_types.source import Compiler, Source +from ethpm_types.utils import AnyUrl ALPHABET = set("abcdefghijklmnopqrstuvwxyz") NUMBERS = set("0123456789") diff --git a/ethpm_types/source.py b/ethpm_types/source.py index 391dea7..3ee42c7 100644 --- a/ethpm_types/source.py +++ b/ethpm_types/source.py @@ -1,24 +1,27 @@ from collections.abc import Iterator from pathlib import Path -from typing import Optional, Union +from typing import TYPE_CHECKING, Optional, Union import requests from cid import make_cid # type: ignore from eth_pydantic_types import HexBytes, HexStr -from pydantic import AnyUrl, RootModel, field_validator, model_serializer, model_validator +from pydantic import RootModel, field_validator, model_serializer, model_validator from pydantic_core import PydanticCustomError from ethpm_types.ast import ASTClassification, ASTNode, SourceLocation from ethpm_types.base import BaseModel from ethpm_types.contract_type import ContractType -from ethpm_types.sourcemap import PCMap from ethpm_types.utils import ( CONTENT_ADDRESSED_SCHEMES, Algorithm, + AnyUrl, compute_checksum, stringify_dict_for_hash, ) +if TYPE_CHECKING: + from ethpm_types.sourcemap import PCMap + class Compiler(BaseModel): name: str @@ -639,7 +642,7 @@ def ast(self) -> ASTNode: return validate_ast(self.contract_type) @property - def pcmap(self) -> PCMap: + def pcmap(self) -> "PCMap": """The contract type PCMap.""" return validate_pcmap(self.contract_type) @@ -828,7 +831,7 @@ def validate_ast(contract_type: ContractType) -> ASTNode: ) -def validate_pcmap(contract_type: ContractType) -> PCMap: +def validate_pcmap(contract_type: ContractType) -> "PCMap": """ A validator used by :class:`~ethpm_types.source.ContractSource` to ensure the given :class:`~ethpm_types.contract_type.ContractType` diff --git a/ethpm_types/sourcemap.py b/ethpm_types/sourcemap.py index 2a4d679..9b73e61 100644 --- a/ethpm_types/sourcemap.py +++ b/ethpm_types/sourcemap.py @@ -1,10 +1,12 @@ from collections.abc import Iterator -from typing import Optional, Union +from typing import TYPE_CHECKING, Optional, Union from pydantic import RootModel, model_validator from ethpm_types.base import BaseModel -from ethpm_types.utils import SourceLocation + +if TYPE_CHECKING: + from ethpm_types.utils import SourceLocation class SourceMapItem(BaseModel): @@ -125,7 +127,7 @@ class PCMapItem(BaseModel): dev: Optional[str] = None @property - def location(self) -> SourceLocation: + def location(self) -> "SourceLocation": return ( (self.line_start or -1), (self.column_start or -1), diff --git a/ethpm_types/utils.py b/ethpm_types/utils.py index 8c28a38..5064aa8 100644 --- a/ethpm_types/utils.py +++ b/ethpm_types/utils.py @@ -2,11 +2,14 @@ from collections.abc import Sequence from enum import Enum from hashlib import md5, sha3_256, sha256 -from typing import Annotated, Any, Optional +from typing import Annotated, Any, Optional, Union from eth_pydantic_types import HexStr +from pydantic import AnyUrl as _AnyUrl +from pydantic import FileUrl CONTENT_ADDRESSED_SCHEMES = {"ipfs"} +AnyUrl = Union[FileUrl, _AnyUrl] class Algorithm(str, Enum): diff --git a/setup.cfg b/setup.cfg index 666d8ae..726eb5e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,9 +1,10 @@ [flake8] max-line-length = 100 -extend-ignore = E203,E701,PYD002 +ignore = E701,E704,W503,PYD002,TC003,TC006 exclude = venv* .eggs docs build ethpm_types/version.py +type-checking-pydantic-enabled = True diff --git a/setup.py b/setup.py index f41d8d6..6825019 100644 --- a/setup.py +++ b/setup.py @@ -17,18 +17,18 @@ "eth-hash[pysha3]", # For eth-utils address checksumming ], "lint": [ - "black>=24.8.0,<25", # Auto-formatter and linter - "mypy>=1.11.2,<2", # Static type analyzer + "black>=24.10.0,<25", # Auto-formatter and linter + "mypy>=1.13.0,<2", # Static type analyzer "types-setuptools", # Needed for mypy type shed "types-requests", # Needed for mypy type shed "flake8>=7.1.1,<8", # Style linter "flake8-breakpoint>=1.1.0,<2", # Detect breakpoints left in code "flake8-print>=5.0.0,<6", # Detect print statements left in code "isort>=5.13.2,<6", # Import sorting linter - "mdformat>=0.7.17", # Auto-formatter for markdown + "mdformat>=0.7.19", # Auto-formatter for markdown "mdformat-gfm>=0.3.5", # Needed for formatting GitHub-flavored markdown "mdformat-frontmatter>=0.4.1", # Needed for frontmatters-style headers in issue templates - "mdformat-pyproject>=0.0.1", # Allows configuring in pyproject.toml + "mdformat-pyproject>=0.0.2", # Allows configuring in pyproject.toml ], "doc": [ "myst-parser>=1.0.0,<2", # Parse markdown docs diff --git a/tests/test_basemodel.py b/tests/test_basemodel.py index 4a10a2a..d4c4c06 100644 --- a/tests/test_basemodel.py +++ b/tests/test_basemodel.py @@ -7,7 +7,7 @@ @pytest.fixture -def MyModel(): +def MyModel() -> type: class _MyModel(BaseModel): name: str input_types: dict[str, Any]