diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 53be81bdf6..9d70b6c2b5 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -65,7 +65,7 @@ jobs: # TODO: Replace with macos-latest when works again. # https://github.com/actions/setup-python/issues/808 os: [ubuntu-latest, macos-12] # eventually add `windows-latest` - python-version: [3.8, 3.9, "3.10", "3.11"] + python-version: [3.8, 3.9, "3.10", "3.11", "3.12"] env: GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index c7840afd6a..d13f5ae307 100644 --- a/README.md +++ b/README.md @@ -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.8 up to 3.12 - **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`. diff --git a/pyproject.toml b/pyproject.toml index 4e4a146a24..2043cc73a7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ write_to = "src/ape/version.py" # character. [tool.black] line-length = 100 -target-version = ['py38', 'py39', 'py310'] +target-version = ['py38', 'py39', 'py310', 'py311', 'py312'] include = '\.pyi?$' [tool.pytest.ini_options] diff --git a/setup.py b/setup.py index 1b9405b878..472676484f 100644 --- a/setup.py +++ b/setup.py @@ -168,5 +168,6 @@ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ], ) diff --git a/src/ape/_cli.py b/src/ape/_cli.py index 4d604ab61e..3e6b548540 100644 --- a/src/ape/_cli.py +++ b/src/ape/_cli.py @@ -121,7 +121,14 @@ def commands(self) -> Dict: if self._commands: return self._commands - eps: Iterable = entry_points().get(self._CLI_GROUP_NAME, []) + # Update when dropping Python 3.9 support. + _entry_points = entry_points() + eps: Iterable = ( + _entry_points.get(self._CLI_GROUP_NAME, []) + if isinstance(_entry_points, dict) + else entry_points(group=self._CLI_GROUP_NAME) + ) + self._commands = {clean_plugin_name(cmd.name): cmd.load for cmd in eps} return self._commands diff --git a/src/ape/api/projects.py b/src/ape/api/projects.py index 1ace30d142..2689079fb8 100644 --- a/src/ape/api/projects.py +++ b/src/ape/api/projects.py @@ -130,8 +130,8 @@ def cached_manifest(self) -> Optional[PackageManifest]: @property def contracts(self) -> Dict[str, ContractType]: - if self._contracts is not None: - return self._contracts + if contracts := self._contracts: + return contracts contracts = {} for p in self._cache_folder.glob("*.json"): diff --git a/src/ape/managers/project/manager.py b/src/ape/managers/project/manager.py index b8eecf878d..fdf33daa9b 100644 --- a/src/ape/managers/project/manager.py +++ b/src/ape/managers/project/manager.py @@ -468,10 +468,10 @@ def contracts(self) -> Dict[str, ContractType]: Returns: Dict[str, ``ContractType``] """ - if self.local_project.cached_manifest is None: - return self.load_contracts() + if self.local_project.cached_manifest and (contracts := self.local_project.contracts): + return contracts - return self.local_project.contracts + return self.load_contracts() def __getattr__(self, attr_name: str) -> Any: """ diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index fd9b0bb466..c16da27b34 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -1,8 +1,8 @@ import threading import time from contextlib import contextmanager -from distutils.dir_util import copy_tree from pathlib import Path +from shutil import copytree from typing import Optional, cast import pytest @@ -307,7 +307,7 @@ def ds_note_test_contract(eth_tester_provider, vyper_contract_type, owner, get_c @pytest.fixture def project_with_contract(temp_config): with temp_config() as project: - copy_tree(str(APE_PROJECT_FOLDER), str(project.path)) + copytree(str(APE_PROJECT_FOLDER), str(project.path), dirs_exist_ok=True) project.local_project._cached_manifest = None # Clean manifest yield project @@ -318,8 +318,8 @@ def project_with_source_files_contract(temp_config): project_source_dir = APE_PROJECT_FOLDER with temp_config() as project: - copy_tree(str(project_source_dir), str(project.path)) - copy_tree(str(bases_source_dir), f"{project.path}/contracts/") + copytree(str(project_source_dir), str(project.path), dirs_exist_ok=True) + copytree(str(bases_source_dir), f"{project.path}/contracts/", dirs_exist_ok=True) yield project