Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: drop 3.8 support #1983

Merged
merged 15 commits into from
Apr 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest] # eventually add `windows-latest`
python-version: [3.8, 3.9, "3.10", "3.11"]
python-version: [3.9, "3.10", "3.11"]

env:
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Read our [academic platform](https://academy.apeworx.io/) will help you master A
In the latest release, Ape requires:

- Linux or macOS
- Python 3.8 up to 3.11
- Python 3.9 up to 3.11
- **Windows**: Install Windows Subsystem Linux [(WSL)](https://docs.microsoft.com/en-us/windows/wsl/install)

Check your python version in a terminal with `python3 --version`.
Expand Down
8 changes: 3 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,12 @@
install_requires=[
"click>=8.1.6,<9",
"ijson>=3.1.4,<4",
"importlib-metadata", # NOTE: Needed on 3.8 for entry_points `group=` kwarg.
antazoey marked this conversation as resolved.
Show resolved Hide resolved
"ipython>=8.5.0,<9",
"lazyasd>=0.1.4",
"packaging>=23.0,<24",
"pandas>=1.3.0,<2",
"pluggy>=1.3,<2",
"pydantic>=2.5.2,<3",
"pydantic>=2.6.4,<3",
"pydantic-settings>=2.0.3,<3",
"pytest>=6.0,<8.0",
"python-dateutil>=2.8.2,<3",
Expand All @@ -128,7 +127,7 @@
"eip712>=0.2.7,<0.3",
"ethpm-types>=0.6.9,<0.7",
"eth_pydantic_types>=0.1.0,<0.2",
"evmchains>=0.0.6,<0.1",
"evmchains>=0.0.7,<0.1",
"evm-trace>=0.1.5,<0.2",
],
entry_points={
Expand All @@ -147,7 +146,7 @@
"ape_pm=ape_pm._cli:cli",
],
},
python_requires=">=3.8,<4",
python_requires=">=3.9,<4",
extras_require=extras_require,
py_modules=packages_data["__modules__"],
license="Apache-2.0",
Expand All @@ -164,7 +163,6 @@
"Operating System :: MacOS",
"Operating System :: POSIX",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
Expand Down
21 changes: 8 additions & 13 deletions src/ape/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import re
import sys
from gettext import gettext
from typing import Any, Dict, List, Optional, Tuple
from importlib.metadata import entry_points
from typing import Any, Iterable, Optional

import click
import importlib_metadata as metadata
import yaml

from ape.cli import ape_cli_context
Expand All @@ -30,7 +30,7 @@ def display_config(ctx, param, value):


class ApeCLI(click.MultiCommand):
_commands: Optional[Dict] = None
_commands: Optional[dict] = None
_CLI_GROUP_NAME = "ape_cli_subcommands"

def format_commands(self, ctx, formatter) -> None:
Expand All @@ -47,7 +47,7 @@ def format_commands(self, ctx, formatter) -> None:
limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands)

# Split the commands into 3 sections.
sections: Dict[str, List[Tuple[str, str]]] = {
sections: dict[str, list[tuple[str, str]]] = {
"Core": [],
"Plugin": [],
"3rd-Party Plugin": [],
Expand Down Expand Up @@ -114,20 +114,15 @@ def _suggest_cmd(usage_error):
raise usage_error

@property
def commands(self) -> Dict:
def commands(self) -> dict:
if self._commands:
return self._commands

entry_points = metadata.entry_points(group=self._CLI_GROUP_NAME)
if not entry_points:
raise Abort("Missing registered CLI subcommands.")

self._commands = {
clean_plugin_name(entry_point.name): entry_point.load for entry_point in entry_points
}
eps: Iterable = entry_points().get(self._CLI_GROUP_NAME, [])
self._commands = {clean_plugin_name(cmd.name): cmd.load for cmd in eps}
return self._commands

def list_commands(self, ctx) -> List[str]:
def list_commands(self, ctx) -> list[str]:
return list(sorted(self.commands))

def get_command(self, ctx, name) -> Optional[click.Command]:
Expand Down
2 changes: 1 addition & 1 deletion src/ape/api/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ def network_choice(self) -> str:
return f"{self.network.choice}:{self.name}"

@abstractmethod
def make_request(self, rpc: str, parameters: Optional[List] = None) -> Any:
def make_request(self, rpc: str, parameters: Optional[Iterable] = None) -> Any:
"""
Make a raw RPC request to the provider.
Advanced featues such as tracing may utilize this to by-pass unnecessary
Expand Down
8 changes: 3 additions & 5 deletions src/ape/api/query.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from functools import lru_cache
from functools import cache
from typing import Any, Dict, Iterator, List, Optional, Sequence, Set, Type, Union

from ethpm_types.abi import BaseModel, EventABI, MethodABI
Expand All @@ -19,8 +19,7 @@
]


# TODO: Replace with `functools.cache` when Py3.8 dropped
@lru_cache(maxsize=None)
@cache
def _basic_columns(Model: Type[BaseInterfaceModel]) -> Set[str]:
columns = set(Model.model_fields)

Expand All @@ -32,8 +31,7 @@ def _basic_columns(Model: Type[BaseInterfaceModel]) -> Set[str]:
return columns


# TODO: Replace with `functools.cache` when Py3.8 dropped
@lru_cache(maxsize=None)
@cache
def _all_columns(Model: Type[BaseInterfaceModel]) -> Set[str]:
columns = _basic_columns(Model)
# NOTE: Iterate down the series of subclasses of `Model` (e.g. Block and BlockAPI)
Expand Down
11 changes: 6 additions & 5 deletions src/ape/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
import tempfile
import time
import traceback
from collections.abc import Collection
from inspect import getframeinfo, stack
from pathlib import Path
from types import CodeType, TracebackType
from typing import TYPE_CHECKING, Any, Collection, Dict, List, Optional, Union, cast
from typing import TYPE_CHECKING, Any, Optional, Union, cast

import click
from eth_typing import Hash32
Expand Down Expand Up @@ -103,7 +104,7 @@ class ArgumentsLengthError(ContractDataError):
def __init__(
self,
arguments_length: int,
inputs: Union[MethodABI, ConstructorABI, int, List, None] = None,
inputs: Union[MethodABI, ConstructorABI, int, list, None] = None,
**kwargs,
):
prefix = (
Expand All @@ -114,7 +115,7 @@ def __init__(
super().__init__(f"{prefix}.")
return

inputs_ls: List[Union[MethodABI, ConstructorABI, int]] = (
inputs_ls: list[Union[MethodABI, ConstructorABI, int]] = (
inputs if isinstance(inputs, list) else [inputs]
)
if not inputs_ls:
Expand Down Expand Up @@ -642,7 +643,7 @@ def __init__(
super().__init__(provider, *args, **kwargs)


def handle_ape_exception(err: ApeException, base_paths: List[Path]) -> bool:
def handle_ape_exception(err: ApeException, base_paths: list[Path]) -> bool:
"""
Handle a transaction error by showing relevant stack frames,
including custom contract frames added to the exception.
Expand Down Expand Up @@ -719,7 +720,7 @@ class CustomError(ContractLogicError):
def __init__(
self,
abi: ErrorABI,
inputs: Dict[str, Any],
inputs: dict[str, Any],
txn: Optional[FailedTxn] = None,
trace: Optional["TraceAPI"] = None,
contract_address: Optional["AddressType"] = None,
Expand Down
11 changes: 6 additions & 5 deletions src/ape/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
import logging
import sys
import traceback
from collections.abc import Sequence
from enum import IntEnum
from pathlib import Path
from typing import IO, Any, Callable, Dict, Optional, Sequence, Union
from typing import IO, Any, Callable, Optional, Union

import click
from yarl import URL
Expand Down Expand Up @@ -73,8 +74,8 @@ def format(self, record):
if _isatty(sys.stdout) and _isatty(sys.stderr):
# Only color log messages when sys.stdout and sys.stderr are sent to the terminal.
level = LogLevel(record.levelno)
default_dict: Dict[str, Any] = {}
styles: Dict[str, Any] = CLICK_STYLE_KWARGS.get(level, default_dict)
default_dict: dict[str, Any] = {}
styles: dict[str, Any] = CLICK_STYLE_KWARGS.get(level, default_dict)
record.levelname = click.style(record.levelname, **styles)

path = Path(record.pathname)
Expand All @@ -89,7 +90,7 @@ def format(self, record):

class ClickHandler(logging.Handler):
def __init__(
self, echo_kwargs: Dict, handlers: Optional[Sequence[Callable[[str], str]]] = None
self, echo_kwargs: dict, handlers: Optional[Sequence[Callable[[str], str]]] = None
):
super().__init__()
self.echo_kwargs = echo_kwargs
Expand All @@ -112,7 +113,7 @@ def emit(self, record):

class ApeLogger:
_mentioned_verbosity_option = False
_extra_loggers: Dict[str, logging.Logger] = {}
_extra_loggers: dict[str, logging.Logger] = {}

def __init__(
self,
Expand Down
7 changes: 4 additions & 3 deletions src/ape_accounts/accounts.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import json
from collections.abc import Iterator
from os import environ
from pathlib import Path
from typing import Any, Dict, Iterator, Optional, Tuple
from typing import Any, Optional

import click
from eip712.messages import EIP712Message
Expand Down Expand Up @@ -32,7 +33,7 @@ def __init__(self):


class AccountContainer(AccountContainerAPI):
loaded_accounts: Dict[str, "KeyfileAccount"] = {}
loaded_accounts: dict[str, "KeyfileAccount"] = {}

@property
def _keyfiles(self) -> Iterator[Path]:
Expand Down Expand Up @@ -292,7 +293,7 @@ def _write_and_return_account(alias: str, passphrase: str, account: LocalAccount

def generate_account(
alias: str, passphrase: str, hd_path: str = ETHEREUM_DEFAULT_PATH, word_count: int = 12
) -> Tuple[KeyfileAccount, str]:
) -> tuple[KeyfileAccount, str]:
"""
Generate a new account.

Expand Down
15 changes: 8 additions & 7 deletions src/ape_cache/query.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from collections.abc import Iterator
from pathlib import Path
from typing import Any, Dict, Iterator, List, Optional, cast
from typing import Any, Optional, cast

from sqlalchemy import create_engine, func
from sqlalchemy.engine import CursorResult
Expand Down Expand Up @@ -326,7 +327,7 @@ def _perform_block_query(self, query: BlockQuery) -> Iterator[BlockAPI]:
)

@perform_query.register
def _perform_transaction_query(self, query: BlockTransactionQuery) -> Iterator[Dict]:
def _perform_transaction_query(self, query: BlockTransactionQuery) -> Iterator[dict]:
with self.database_connection as conn:
result = conn.execute(
select([Transactions]).where(Transactions.block_hash == query.block_id)
Expand Down Expand Up @@ -395,7 +396,7 @@ def _cache_update_events_clause(self, query: ContractEventQuery) -> Insert:
@singledispatchmethod
def _get_cache_data(
self, query: QueryType, result: Iterator[BaseInterfaceModel]
) -> Optional[List[Dict[str, Any]]]:
) -> Optional[list[dict[str, Any]]]:
raise QueryEngineError(
"""
Not a compatible QueryType. For more details see our docs
Expand All @@ -406,16 +407,16 @@ def _get_cache_data(
@_get_cache_data.register
def _get_block_cache_data(
self, query: BlockQuery, result: Iterator[BaseInterfaceModel]
) -> Optional[List[Dict[str, Any]]]:
) -> Optional[list[dict[str, Any]]]:
return [m.model_dump(mode="json", by_alias=False) for m in result]

@_get_cache_data.register
def _get_block_txns_data(
self, query: BlockTransactionQuery, result: Iterator[BaseInterfaceModel]
) -> Optional[List[Dict[str, Any]]]:
) -> Optional[list[dict[str, Any]]]:
new_result = []
table_columns = [c.key for c in Transactions.__table__.columns] # type: ignore
txns: List[TransactionAPI] = cast(List[TransactionAPI], result)
txns: list[TransactionAPI] = cast(list[TransactionAPI], result)
for val in [m for m in txns]:
new_dict = {
k: v
Expand Down Expand Up @@ -443,7 +444,7 @@ def _get_block_txns_data(
@_get_cache_data.register
def _get_cache_events_data(
self, query: ContractEventQuery, result: Iterator[BaseInterfaceModel]
) -> Optional[List[Dict[str, Any]]]:
) -> Optional[list[dict[str, Any]]]:
return [m.model_dump(mode="json", by_alias=False) for m in result]

def update_cache(self, query: QueryType, result: Iterator[BaseInterfaceModel]):
Expand Down
4 changes: 2 additions & 2 deletions src/ape_compile/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from pathlib import Path
from typing import List, Optional
from typing import Optional

from pydantic import field_validator, model_validator

Expand All @@ -21,7 +21,7 @@ class Config(PluginConfig):
should configure ``include_dependencies`` to be ``True``.
"""

exclude: List[str] = ["*package.json", "*package-lock.json", "*tsconfig.json"]
exclude: list[str] = ["*package.json", "*package-lock.json", "*tsconfig.json"]
"""
Source exclusion globs across all file types.
"""
Expand Down
5 changes: 2 additions & 3 deletions src/ape_compile/_cli.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from pathlib import Path
from typing import Dict, Set

import click
from ethpm_types import ContractType
Expand Down Expand Up @@ -38,7 +37,7 @@ def _include_dependencies_callback(ctx, param, value):
callback=_include_dependencies_callback,
)
@ape_cli_context()
def cli(cli_ctx, file_paths: Set[Path], use_cache: bool, display_size: bool, include_dependencies):
def cli(cli_ctx, file_paths: set[Path], use_cache: bool, display_size: bool, include_dependencies):
"""
Compiles the manifest for this project and saves the results
back to the manifest.
Expand Down Expand Up @@ -97,7 +96,7 @@ def cli(cli_ctx, file_paths: Set[Path], use_cache: bool, display_size: bool, inc
_display_byte_code_sizes(cli_ctx, contract_types)


def _display_byte_code_sizes(cli_ctx, contract_types: Dict[str, ContractType]):
def _display_byte_code_sizes(cli_ctx, contract_types: dict[str, ContractType]):
# Display bytecode size for *all* contract types (not just ones we compiled)
code_size = []
for contract in contract_types.values():
Expand Down
8 changes: 4 additions & 4 deletions src/ape_console/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from importlib.util import module_from_spec, spec_from_loader
from os import environ, getcwd
from types import ModuleType
from typing import Any, Dict, cast
from typing import Any, cast

import click
import IPython
Expand Down Expand Up @@ -46,7 +46,7 @@ def import_extras_file(file_path) -> ModuleType:
return module


def load_console_extras(**namespace: Any) -> Dict[str, Any]:
def load_console_extras(**namespace: Any) -> dict[str, Any]:
"""load and return namespace updates from ape_console_extras.py files if
they exist"""
global_extras = ManagerAccessMixin.config_manager.DATA_FOLDER.joinpath(CONSOLE_EXTRAS_FILENAME)
Expand All @@ -66,7 +66,7 @@ def load_console_extras(**namespace: Any) -> Dict[str, Any]:
# Figure out the kwargs the func is looking for and assemble
# from the original namespace
func_spec = inspect.getfullargspec(ape_init_extras)
init_kwargs: Dict[str, Any] = {k: namespace.get(k) for k in func_spec.args}
init_kwargs: dict[str, Any] = {k: namespace.get(k) for k in func_spec.args}

# Execute functionality with existing console namespace as
# kwargs.
Expand Down Expand Up @@ -140,7 +140,7 @@ def console(project=None, verbose=None, extra_locals=None, embed=False):
_launch_console(namespace, ipy_config, embed, banner)


def _launch_console(namespace: Dict, ipy_config: IPythonConfig, embed: bool, banner: str):
def _launch_console(namespace: dict, ipy_config: IPythonConfig, embed: bool, banner: str):
ipython_kwargs = {"user_ns": namespace, "config": ipy_config}
if embed:
IPython.embed(**ipython_kwargs, colors="Neutral", banner1=banner)
Expand Down
Loading
Loading