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!: pydantic v2 upgrade [APE-1413] #1674

Merged
merged 22 commits into from
Dec 9, 2023
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 .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ repos:
- id: flake8

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.7.0
rev: v1.7.1
hooks:
- id: mypy
additional_dependencies: [
Expand Down
2 changes: 1 addition & 1 deletion docs/userguides/console.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ If you include a function named `ape_init_extras`, it will be executed with the

```python
def ape_init_extras(chain):
return {"web3": chain.provider._web3}
return {"web3": chain.provider.web3}
```

Then `web3` will be available to use immediately.
Expand Down
2 changes: 1 addition & 1 deletion docs/userguides/contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ In the example above, the bytes value returned contains the method ID selector p
Alternatively, you can decode input:

```python
from ethpm_types import HexBytes
from eth_pydantic_types import HexBytes
from ape import Contract

contract = Contract("0x...")
Expand Down
22 changes: 11 additions & 11 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,28 @@

extras_require = {
"test": [ # `test` GitHub Action jobs uses this
"pytest-xdist", # multi-process runner
"pytest-xdist", # Multi-process runner
"pytest-cov>=4.0.0,<5", # Coverage analyzer plugin
"pytest-mock", # For creating mocks
"hypothesis>=6.2.0,<7.0", # Strategy-based fuzzer
"hypothesis-jsonschema==0.19.0", # JSON Schema fuzzer extension
],
"lint": [
"black>=23.11.0,<24", # Auto-formatter and linter
"mypy>=1.7.0,<2", # Static type analyzer
"mypy>=1.7.1,<2", # Static type analyzer
"types-PyYAML", # Needed due to mypy typeshed
"types-requests", # Needed due to mypy typeshed
"types-setuptools", # Needed due to mypy typeshed
"pandas-stubs==1.2.0.62", # Needed due to mypy typeshed
"types-SQLAlchemy>=1.4.49", # Needed due to mypy typeshed
"flake8>=6.1.0,<7", # Style linter
"flake8-breakpoint>=1.1.0,<2", # detect breakpoints left in code
"flake8-print>=4.0.1,<5", # detect print statements left in code
"flake8-breakpoint>=1.1.0,<2", # Detect breakpoints left in code
"flake8-print>=4.0.1,<5", # Detect print statements left in code
"isort>=5.10.1,<6", # Import sorting linter
"mdformat>=0.7.17", # 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
"pydantic<2.0", # Needed for successful type check. TODO: Remove after full v2 support.
],
"doc": [
"myst-parser>=1.0.0,<2", # Parse markdown docs
Expand Down Expand Up @@ -102,7 +101,8 @@
"packaging>=23.0,<24",
"pandas>=1.3.0,<2",
"pluggy>=1.3,<2",
"pydantic>=1.10.8,<3",
"pydantic>=2.5.0,<3",
"pydantic-settings>=2.0.3,<3",
"PyGithub>=1.59,<2",
"pytest>=6.0,<8.0",
"python-dateutil>=2.8.2,<3",
Expand All @@ -119,13 +119,13 @@
"eth-account>=0.8,<0.9",
"eth-typing>=3.4,<4",
"eth-utils>=2.2.0,<3",
"hexbytes>=0.2.3,<1",
"py-geth>=3.13.0,<4",
"web3[tester]>=6.7.0,<7",
"web3[tester]>=6.11.4,<7",
# ** Dependencies maintained by ApeWorX **
"eip712>=0.2.1,<0.3",
"ethpm-types>=0.5.10,<0.6",
"evm-trace>=0.1.0a23",
"eip712>=0.2.2,<0.3",
"ethpm-types>=0.6.1,<0.7",
"eth_pydantic_types>=0.1.0a4,<0.2",
"evm-trace>=0.1.0",
],
entry_points={
"console_scripts": ["ape=ape._cli:cli"],
Expand Down
2 changes: 1 addition & 1 deletion src/ape/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def display_config(ctx, param, value):
from ape import project

click.echo("# Current configuration")
click.echo(yaml.dump(project.config_manager.dict()))
click.echo(yaml.dump(project.config_manager.model_dump(mode="json")))

ctx.exit() # NOTE: Must exit to bypass running ApeCLI

Expand Down
47 changes: 0 additions & 47 deletions src/ape/_pydantic_compat.py

This file was deleted.

7 changes: 5 additions & 2 deletions src/ape/api/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,10 +462,13 @@ def __contains__(self, address: AddressType) -> bool:

def _verify_account_type(self, account):
if not isinstance(account, self.account_type):
container_type_name = getattr(type(account), "__name__", "<CustomContainerType>")
account_type_name = getattr(self.account_type, "__name__", "<UnknownAccount>")
message = (
f"Container '{type(account).__name__}' is an incorrect "
f"type for container '{type(self.account_type).__name__}'."
f"Container '{container_type_name}' is an incorrect "
f"type for container '{account_type_name}'."
)

raise AccountsError(message)

def _verify_unused_alias(self, account):
Expand Down
5 changes: 3 additions & 2 deletions src/ape/api/address.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import TYPE_CHECKING, Any, List

from ethpm_types import HexBytes
from eth_pydantic_types import HexBytes

from ape.exceptions import ConversionError
from ape.types import AddressType, ContractCode
Expand Down Expand Up @@ -70,7 +70,8 @@ def __dir__(self) -> List[str]:
return self._base_dir_values

def __repr__(self) -> str:
return f"<{self.__class__.__name__} {self.address}>"
cls_name = getattr(type(self), "__name__", BaseAddress.__name__)
return f"<{cls_name} {self.address}>"

def __str__(self) -> str:
"""
Expand Down
10 changes: 6 additions & 4 deletions src/ape/api/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from pathlib import Path
from typing import Dict, Iterator, List, Optional, Set, Tuple

from ethpm_types import ContractType, HexBytes
from eth_pydantic_types import HexBytes
from ethpm_types import ContractType
from ethpm_types.source import Content, ContractSource
from evm_trace.geth import TraceFrame as EvmTraceFrame
from evm_trace.geth import create_call_node_data
Expand Down Expand Up @@ -49,8 +50,8 @@ def settings(self) -> PluginConfig:
The combination of settings from ``ape-config.yaml`` and ``.compiler_settings``.
"""
CustomConfig = self.config.__class__
data = {**self.config.dict(), **self.compiler_settings}
return CustomConfig.parse_obj(data)
data = {**self.config.model_dump(mode="json", by_alias=True), **self.compiler_settings}
return CustomConfig.model_validate(data)

@abstractmethod
def get_versions(self, all_paths: List[Path]) -> Set[str]:
Expand Down Expand Up @@ -157,7 +158,8 @@ def get_version_map( # type: ignore[empty-body]
"""

def __repr__(self) -> str:
return f"<{self.__class__.__name__} {self.name}>"
cls_name = getattr(type(self), "__name__", CompilerAPI.__name__)
return f"<{cls_name} {self.name}>"

def __str__(self) -> str:
return self.name
Expand Down
13 changes: 4 additions & 9 deletions src/ape/api/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from enum import Enum
from typing import Any, Dict, Optional, TypeVar

from ape._pydantic_compat import BaseModel, BaseSettings
from pydantic import ConfigDict
from pydantic_settings import BaseSettings

T = TypeVar("T")

Expand All @@ -14,10 +15,6 @@ class ConfigEnum(str, Enum):
"""


class ConfigDict(BaseModel):
__root__: dict = {}


class PluginConfig(BaseSettings):
"""
A base plugin configuration class. Each plugin that includes
Expand All @@ -26,7 +23,7 @@ class PluginConfig(BaseSettings):

@classmethod
def from_overrides(cls, overrides: Dict) -> "PluginConfig":
default_values = cls().dict()
default_values = cls().model_dump()

def update(root: Dict, value_map: Dict):
for key, val in value_map.items():
Expand Down Expand Up @@ -54,9 +51,7 @@ def get(self, key: str, default: Optional[T] = None) -> T:
return self.__dict__.get(key, default)


class GenericConfig(PluginConfig):
class GenericConfig(ConfigDict):
"""
The default class used when no specialized class is used.
"""

__root__: dict = {}
2 changes: 1 addition & 1 deletion src/ape/api/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
ConvertedType = TypeVar("ConvertedType")


class ConverterAPI(Generic[ConvertedType], BaseInterfaceModel):
class ConverterAPI(BaseInterfaceModel, Generic[ConvertedType]):
@abstractmethod
def is_convertible(self, value: Any) -> bool:
"""
Expand Down
16 changes: 9 additions & 7 deletions src/ape/api/networks.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@
encode_transaction,
serializable_unsigned_transaction_from_dict,
)
from eth_pydantic_types import HexBytes
from eth_utils import keccak, to_int
from ethpm_types import ContractType, HexBytes
from ethpm_types import BaseModel, ContractType
from ethpm_types.abi import ABIType, ConstructorABI, EventABI, MethodABI
from pydantic import computed_field

from ape._pydantic_compat import BaseModel
from ape.exceptions import (
NetworkError,
NetworkMismatchError,
Expand Down Expand Up @@ -88,6 +89,7 @@ class EcosystemAPI(BaseInterfaceModel):
"""The number of the decimals the fee token has."""

_default_network: Optional[str] = None
"""The default network of the ecosystem, such as ``local``."""

def __repr__(self) -> str:
return f"<{self.name}>"
Expand Down Expand Up @@ -152,8 +154,7 @@ def serialize_transaction(self, transaction: "TransactionAPI") -> bytes:
if not self.signature:
raise SignatureError("The transaction is not signed.")

txn_data = self.dict(exclude={"sender"})

txn_data = self.model_dump(exclude={"sender"})
unsigned_txn = serializable_unsigned_transaction_from_dict(txn_data)
signature = (
self.signature.v,
Expand Down Expand Up @@ -267,7 +268,6 @@ def default_network(self) -> str:
Returns:
str
"""

if network := self._default_network:
# Was set programatically.
return network
Expand All @@ -285,7 +285,7 @@ def default_network(self) -> str:
return self.networks[0]

# Very unlikely scenario.
raise ValueError("No networks found.")
raise NetworkError("No networks found.")

def set_default_network(self, network_name: str):
"""
Expand Down Expand Up @@ -506,7 +506,7 @@ def get_method_selector(self, abi: MethodABI) -> HexBytes:
Override example::

from ape.api import EcosystemAPI
from ethpm_types import HexBytes
from eth_pydantic_types import HexBytes

class MyEcosystem(EcosystemAPI):
def get_method_selector(self, abi: MethodABI) -> HexBytes:
Expand Down Expand Up @@ -700,6 +700,7 @@ class NetworkAPI(BaseInterfaceModel):
request_header: Dict
"""A shareable network HTTP header."""

# See ``.default_provider`` which is the proper field.
_default_provider: str = ""

@classmethod
Expand Down Expand Up @@ -982,6 +983,7 @@ def use_provider(
provider = self.get_provider(provider_name=provider_name, provider_settings=settings)
return ProviderContextManager(provider=provider, disconnect_after=disconnect_after)

@computed_field() # type: ignore[misc]
@property
def default_provider(self) -> Optional[str]:
"""
Expand Down
Loading
Loading