Skip to content

Commit

Permalink
refactor: project
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey committed Mar 19, 2024
1 parent a8d1487 commit 8b8be57
Show file tree
Hide file tree
Showing 86 changed files with 4,522 additions and 4,914 deletions.
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.8.0
rev: v1.9.0
hooks:
- id: mypy
additional_dependencies: [
Expand Down
5 changes: 4 additions & 1 deletion docs/userguides/accounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,12 @@ Here is an example with custom EIP-712 classes:
from ape import accounts
from eip712.messages import EIP712Message, EIP712Type


class Person(EIP712Type):
name: "string"
wallet: "address"


class Mail(EIP712Message):
_chainId_: "uint256" = 1
_name_: "string" = "Ether Mail"
Expand All @@ -292,7 +294,8 @@ class Mail(EIP712Message):
sender: Person
receiver: Person

alice = Person(name="Alice", wallet="0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826")

alice = Person(name="Alice", wallet="0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826")
bob = Person("Bob", "0xB0B0b0b0b0b0B000000000000000000000000000")
message = Mail(sender=alice, receiver=bob)

Expand Down
31 changes: 18 additions & 13 deletions docs/userguides/clis.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,20 @@ In Ape, it is easy to extend the CLI context object and use the extended version
from ape.cli import ApeCliContextObject, ape_cli_context
import click


class MyManager:
"""My custom manager."""
"""My custom manager."""


class CustomContext(ApeCliContextObject):
"""Add new managers to your custom context"""
my_manager: MyManager = MyManager()

@property
def signer(self):
"""Utilize existing managers in your custom context."""
return self.account_manager.load("my_account")
"""Add new managers to your custom context"""
my_manager: MyManager = MyManager()

@property
def signer(self):
"""Utilize existing managers in your custom context."""
return self.account_manager.load("my_account")


@click.command()
@ape_cli_context(obj_type=CustomContext)
Expand Down Expand Up @@ -203,17 +206,19 @@ from ape_accounts.accounts import KeyfileAccount
# NOTE: This is just an example and not anything specific or recommended.
APPLICATION_PREFIX = "<FOO_BAR>"


@click.command()
@existing_alias_argument(account_type=KeyfileAccount)
def cli_0(alias):
pass

pass


@click.command()
@existing_alias_argument(account_type=lambda a: a.alias.startswith(APPLICATION_PREFIX))
def cli_1(alias):
pass
pass


# Select from the given accounts directly.
my_accounts = [accounts.load("me"), accounts.load("me2")]
selected_account = get_user_selected_account(account_type=my_accounts)
Expand Down
7 changes: 3 additions & 4 deletions docs/userguides/contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,6 @@ Here is an example of how you can use the multicall module:
import ape
from ape_ethereum import multicall


ADDRESSES = ("0xF4b8A02D4e8D76070bD7092B54D2cBbe90fa72e9", "0x80067013d7F7aF4e86b3890489AcAFe79F31a4Cb")
POOLS = [ape.project.IPool.at(a) for a in ADDRESSES]

Expand All @@ -409,14 +408,14 @@ def main():
call = multicall.Call()
for pool in POOLS:
call.add(pool.getReserves)

print(list(call()))

# Use multi-transaction.
tx = multicall.Transaction()
for pool in POOLS:
tx.add(pool.ApplyDiscount, 123)

acct = ape.accounts.load("signer")
for result in tx(sender=acct):
print(result)
Expand Down
7 changes: 4 additions & 3 deletions docs/userguides/data.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ Each account within ape will also fetch and store transactional data that you ca
To work with an account's transaction data, you can do stuff like this:

```python
In [1]: chain.history["example.eth"].query("value").sum() # All value sent by this address
In [2]: acct = accounts.load("my-acct"); acct.history[-1] # Last txn `acct` made
In [3]: acct.history.query("total_fees_paid").sum() # Sum of ether paid for fees by `acct`
In[1]: chain.history["example.eth"].query("value").sum() # All value sent by this address
In[2]: acct = accounts.load("my-acct");
acct.history[-1] # Last txn `acct` made
In[3]: acct.history.query("total_fees_paid").sum() # Sum of ether paid for fees by `acct`
```

## Getting Contract Event Data
Expand Down
15 changes: 8 additions & 7 deletions docs/userguides/dependencies.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Dependencies

Ape downloads and caches dependencies in the `.ape/packages/<name>/<version-id>` directory where `<name>` refers to the name of the dependency and `<version-id>` refers to the version or branch of the package.
Ape downloads and caches dependencies in the `.ape/packages/projects/<name>/<version-id>` directory where `<name>` refers to the name of the dependency and `<version-id>` refers to the version or branch of the package.
When first downloading dependencies, Ape only places the source contents in the `sources` field of the `PackageManifest` and leaves the `contract_types` field untouched.
This is because dependencies may not compile by Ape's standard out-of-the-box but their contract types can still be used in projects that do.

Expand Down Expand Up @@ -141,25 +141,25 @@ For `npm` dependencies, you use an `npm:` prefix.
For local dependencies, you give it a path to the local dependency.
`--version` is not required when using a local dependency.

### remove
### uninstall

Remove previously installed packages using the `remove` command:
Remove previously installed packages using the `uninstall` command:

```shell
ape pm remove OpenZeppelin
ape pm uninstall OpenZeppelin
```

If there is a single version installed, the command will remove the single version.
If multiple versions are installed, pass additional arguments specifying the version(s) to be removed:

```shell
ape pm remove OpenZeppelin 4.5.0 4.6.0
ape pm uninstall OpenZeppelin 4.5.0 4.6.0
```

To skip the confirmation prompts, use the `--yes` flag (abbreviated as `-y`):

```shell
ape pm remove OpenZeppelin all --yes
ape pm uninstall OpenZeppelin all --yes
```

**NOTE**: Additionally, use the `all` special version key to delete all versions.
Expand Down Expand Up @@ -266,7 +266,8 @@ You can achieve this using the project manager:
from ape import accounts, project
# NOTE: This will compile the dependency
dependency_contract = project.dependencies["my_dependency"]["1.0.0"].DependencyContractType
dependency = project.dependencies["my_dependency"]["1.0.0"]
dependency_contract = dependency.project.DependencyContractType
my_account = accounts.load("alias")
deployed_contract = my_account.deploy(dependency_contract, "argument")
print(deployed_contract.address)
Expand Down
72 changes: 32 additions & 40 deletions docs/userguides/projects.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,64 +17,56 @@ project # The root project directory
Notice that you can configure you ape project using the `ape-config.yaml` file.
See the [configuration guide](./config.html) for a more detailed explanation of settings you can adjust.

## Adding Plugins
## The Local Project

Your project may require plugins.
To install plugins, use the `ape plugins install .` command.
Learn more about configuring your project's required plugins by following [this guide](./installing_plugins.html).

## Compiling Contracts

The project manager object is a representation of your current project.
Access it from the root `ape` namespace:
After you have a local project and you are in the directory of that project, the global `project` reference in Ape will refer to this project.
You can see this by typing `project` in the `ape console`:

```python
from ape import project
```

Your `project` contains all the "relevant" files, such as source files in the `contracts/` directory.
Use the following command to compile all contracts in the `contracts/` directory:

```bash
ape compile
In [1]: project
Out[1]: <ProjectManager ~/ApeProjects/ape-demo-project>
```

For more information on compiling your project, see [this guide](./compile.html).
In this case, my terminal's current working directory is the same as a local project named `ape-demo-project`.

## Deploying Contracts
## Other Projects

After compiling, the contract containers are accessible from the `project` manager.
Deploy them in the `console` or in scripts; for example:
You can reference other local projects on your computer by using the `Project` factory class (notice the capital `P`):

```python
from ape import accounts, project
from ape import Project

account = accounts.load("my_account_alias")
account.deploy(project.MyContract)
my_other_project = Project("../path/to/my/other/project")
_ = my_other_project.MyContract # Do anything you can do to the root-level project.
```

**NOTE**: You can also deploy contracts from the container itself:
## Project Manifests

Ape stores and caches artifacts in an [EthPM package manifest](https://eips.ethereum.org/EIPS/eip-2678).
When working with local projects, the manifests get placed in the `<project-path>/.build/__local__.json`.
However, you may obtain a manifest from a different location.
If that is the case, you can create a project directly from the manifest itself:

```python
from ape import accounts, project
from ape import Project

account = accounts.load("my_account_alias")
project.MyContract.deploy(sender=account)
# Pass in a manifest (object or dictionary), or a path to a manifest's JSON file.
project = Project.from_manifest("path/to/manifest.json")
_ = project.MyContract # Do anything you can do to the root-level project.
```

### Dependencies

To set up and use dependencies in your project, follow [this guide](./dependencies.html).
## Dependencies

## Scripts
Use other projects as dependencies in Ape.
There is an extensive guide you can read on this [here](./dependencies.html).
But it is important to note that the dependency system largely is dependent on the project system.
Dependencies are just projects after all; projects containing source files you both use in your projects or compile independently.

The scripts folder contains project automation scripts, such as deploy scripts, as well as other executable jobs, such as scripts for running simulations.
To learn more about scripting in Ape, see [the scripting guide](./scripts.html).
For example, access a dependency project and treat it like any other project this way:

## Testing
```python
from ape import project

Use tests to verify your project.
You can test your project using the `ape test` command.
The `ape test` command comes with the core-plugin `ape-test`.
The `ape-test` plugin extends the popular python testing framework [pytest](https://docs.pytest.org/en/6.2.x/contents.html).
Testing is a complex topic; learn more about testing using Ape framework [here](./testing.html).
dependency = project.dependencies.get_dependency("my-dependency", "1.0.0")
contract_type = dependency.project.ContractFromDependency
```
6 changes: 3 additions & 3 deletions docs/userguides/publishing.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Once your project has successfully compiled, you will have the start of your `Pa

## Tracking Deployments

If your project contains deployments that you wish to include in its package manifest, use the [track_deployment()](../methoddocs/managers.html#ape.managers.project.manager.ProjectManager.track_deployment) method.
If your project contains deployments that you wish to include in its package manifest, use the [project.deployments.track](../methoddocs/managers.html#ape.managers.project.manager.DeploymentManager.track) method.
Example:

```python
Expand All @@ -26,7 +26,7 @@ account = accounts.load("mainnet-account")

# Assume your project has a contract named 'MyContract' with constructor that accepts argument '123'.
contract = project.MyContract.deploy(123, sender=account)
project.track_deployment(contract)
project.deployments.track(contract)
```

If the contract is already deployed, you can use [Contract](../methoddocs/ape.html#ape.Contract) to get a contract instance:
Expand All @@ -35,7 +35,7 @@ If the contract is already deployed, you can use [Contract](../methoddocs/ape.ht
from ape import Contract, project

contract = Contract("0x12c17f958d2ee523a2206206994597c13d831e34")
project.track_deployment(contract)
project.deployments.track(contract)
```

For more information on accessing contract instances, follow [this guide](./contracts.html).
Expand Down
6 changes: 3 additions & 3 deletions docs/userguides/transactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ ape console --network ethereum:goerli:alchemy
This will launch an IPython shell:

```python
In [1]: dev = accounts.load("dev")
In [2]: token = dev.deploy(project.Token)
In [3]: token.contract_method_defined_in_contract()
In[1]: dev = accounts.load("dev")
In[2]: token = dev.deploy(project.Token)
In[3]: token.contract_method_defined_in_contract()
```

For an in depth tutorial on how to deploy, please visit [ApeAcademy](https://academy.apeworx.io/).
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
],
"lint": [
"black>=24.2.0,<25", # Auto-formatter and linter
"mypy>=1.8.0,<2", # Static type analyzer
"mypy>=1.9.0,<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
Expand All @@ -36,7 +36,7 @@
"mdformat-pyproject>=0.0.1", # Allows configuring in pyproject.toml
],
"doc": [
"pygments>=2.17.0,<3", # Needed for the Vyper lexer
"pygments>=2.17.2,<3", # Needed for the Vyper lexer
"myst-parser>=1.0.0,<2", # Parse markdown docs
"sphinx-click>=4.4.0,<5", # For documenting CLI
"Sphinx>=6.1.3,<7", # Documentation generator
Expand Down
4 changes: 3 additions & 1 deletion src/ape/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import re
import sys
from gettext import gettext
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple

import click
Expand Down Expand Up @@ -80,7 +81,8 @@ def invoke(self, ctx) -> Any:
except click.UsageError as err:
self._suggest_cmd(err)
except ApeException as err:
if handle_ape_exception(err, [ctx.obj.project_manager.path]):
path = ctx.obj.project_manager.path
if isinstance(path, Path) and handle_ape_exception(err, [path]):
# All exc details already outputted.
sys.exit(1)
else:
Expand Down
11 changes: 9 additions & 2 deletions src/ape/api/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,10 @@ def deploy(
self.chain_manager.contracts.cache_deployment(instance)

if publish:
self.project_manager.track_deployment(instance)
self.project_manager.deployments.track(instance)
self.provider.network.publish_contract(address)

instance.base_path = contract.base_path or self.project_manager.path
return instance

def declare(self, contract: "ContractContainer", *args, **kwargs) -> ReceiptAPI:
Expand Down Expand Up @@ -374,7 +375,7 @@ class AccountContainerAPI(BaseInterfaceModel):
instances.
"""

data_folder: Path
name: str

account_type: Type[AccountAPI]

Expand All @@ -398,6 +399,12 @@ def accounts(self) -> Iterator[AccountAPI]:
Iterator[:class:`~ape.api.accounts.AccountAPI`]
"""

@property
def data_folder(self) -> Path:
path = self.config_manager.DATA_FOLDER / self.name
path.mkdir(parents=True, exist_ok=True)
return path

@abstractmethod
def __len__(self) -> int:
"""
Expand Down
Loading

0 comments on commit 8b8be57

Please sign in to comment.