Skip to content
Open
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
12 changes: 12 additions & 0 deletions basics/anchorpy-main/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
test:
poetry run pytest -vv

init-clientgen-examples:
cd tests/client_gen/example-program/ && anchor idl parse -f programs/example-program/src/lib.rs -o ../../idls/clientgen_example_program.json && cd ../../.. && poetry run anchorpy client-gen tests/idls/clientgen_example_program.json tests/client_gen/example_program_gen --program-id 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8 --pdas
poetry run anchorpy client-gen tests/idls/basic_2.json examples/client-gen/basic_2 --program-id 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8
poetry run anchorpy client-gen tests/idls/tictactoe.json examples/client-gen/tictactoe --program-id 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8
poetry run anchorpy client-gen tests/idls/spl_token.json tests/client_gen/token --program-id TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA

lint:
poetry run ruff src tests
poetry run mypy src tests
38 changes: 38 additions & 0 deletions basics/anchorpy-main/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# AnchorPy


AnchorPy is the gateway to interacting with [Anchor](https://github.com/project-serum/anchor) programs in Python.
It provides:

- A static client generator
- A dynamic client similar to `anchor-ts`
- A Pytest plugin
- A CLI with various utilities for Anchor Python development.




## Installation (requires Python >=3.9)

```sh
pip install anchorpy[cli]

```
Or, if you're not using the CLI features of AnchorPy you can just run `pip install anchorpy`.

### Development Setup

If you want to contribute to AnchorPy, follow these steps to get set up:

1. Install [poetry](https://python-poetry.org/docs/#installation)
2. Install dev dependencies:
```sh
poetry install

```
3. Install [nox-poetry](https://github.com/cjolowicz/nox-poetry) (note: do not use Poetry to install this, see [here](https://medium.com/@cjolowicz/nox-is-a-part-of-your-global-developer-environment-like-poetry-pre-commit-pyenv-or-pipx-1cdeba9198bd))
4. Activate the poetry shell:
```sh
poetry shell

```
80 changes: 80 additions & 0 deletions basics/anchorpy-main/docs/cli/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# AnchorPy CLI

AnchorPy comes with a CLI to make your life easier when using Python with Anchor.


```console
$ anchorpy --help
Usage: anchorpy [OPTIONS] COMMAND [ARGS]...

AnchorPy CLI.

Options:
--install-completion [bash|zsh|fish|powershell|pwsh]
Install completion for the specified shell.
--show-completion [bash|zsh|fish|powershell|pwsh]
Show completion for the specified shell, to
copy it or customize the installation.
--help Show this message and exit.

Commands:
init Create a basic Python test file for an Anchor program.
shell Start IPython shell with AnchorPy workspace object initialized.
```

## Commands

### Init

```console
$ anchorpy init --help
Usage: anchorpy init [OPTIONS] PROGRAM_NAME

Create a basic Python test file for an Anchor program.

This does not replace `anchor init`, but rather should be run after it.

The test file will live at `tests/test_$PROGRAM_NAME.py`.

Arguments:
PROGRAM_NAME The name of the Anchor program. [required]

Options:
--help Show this message and exit.
```

### Shell

```console
$ anchorpy shell --help
Usage: anchorpy shell [OPTIONS]

Start IPython shell with AnchorPy workspace object initialized.

Note that you should run `anchor localnet` before `anchorpy shell`.

Options:
--help Show this message and exit.
```

#### Example

<div class="termy">

```console
$ cd anchor/examples/tutorial/basic-0 && anchorpy shell
Python 3.9.1 (default, Dec 11 2020, 14:32:07)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.30.1 -- An enhanced Interactive Python. Type '?' for help.

Hint: type `workspace` to see the Anchor workspace object.

# In [1]:$ await workspace["basic_0"].rpc["initialize"]()
Out[1]: '2q1Z8BcsSBikMLEFoeFGhUukfsNYLJx7y33rMZ57Eh4gAHJxpJ9oP9b9aFyrizh9wcuiVtAAxvmBifCXdqWeNLor'
```

</div>

### Client-gen

See [Client Generator](../clientgen)
206 changes: 206 additions & 0 deletions basics/anchorpy-main/docs/clientgen/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
# Client Generator

The `anchorpy client-gen` command generates a Python client based on an Anchor IDL. This client provides functions for
generating instructions and class definitions for fetching and serializing accounts. The output is very similar
to the Typescript code produced by [anchor-client-gen](https://github.com/kklas/anchor-client-gen).

## Features

- Fully typed.
- Supports all Anchor field types.
- Makes enums and complex types easy to work with.
- Generates error classes for each error.
- Provides `to_json` and `from_json` utility functions for types and accounts.

!!! note
It is recommended to use the generated client instead of the dynamic client where possible, as it is easier to
work with and comes with proper type hints.

## Usage

```console
$ anchorpy client-gen --help
Usage: anchorpy client-gen [OPTIONS] IDL OUT

Generate Python client code from the specified anchor IDL.

Arguments:
IDL Anchor IDL file path [required]
OUT Output directory. [required]

Options:
--program-id TEXT Optional program ID to be included in the code
--help Show this message and exit.

```

## Example

<div class="termy">

```console
$ anchorpy client-gen path/to/idl.json ./my_client
generating package...
generating program_id.py...
generating errors.py...
generating instructions...
generating types...
generating accounts...
```

</div>

This will generate code to `./my_client`:

```
.
├── accounts
│ ├── foo_account.py
│ └── __init__.py
├── instructions
│ ├── some_instruction.py
│ ├── other_instruction.py
│ └── __init__.py
├── types
│ ├── bar_struct.py
│ ├── baz_enum.py
│ └── __init__.py
├── errors
│ ├── anchor.py
│ ├── custom.py
│ └── __init__.py
└── program_id.py
```

## Using the generated client

### Instructions

```python
from solana.transaction import Transaction
from solders.keypair import Keypair
from solders.pubkey import Pubkey
from anchorpy import Provider
from my_client.instructions import some_instruction

# call an instruction
foo_account = Keypair()

ix = some_instruction({
"foo_param": "...",
"bar_param": "...",
...
}, {
"foo_account": foo_account.pubkey(), # signer
"bar_account": Pubkey("..."),
...
})
tx = Transaction().add(ix)

provider = Provider.local()

await provider.send(tx, [payer, foo_account])
```

### Accounts

```python
from solders.pubkey import Pubkey
from my_client.accounts import FooAccount

# fetch an account
addr = Pubkey("...")

acc = await FooAccount.fetch(connection, addr)
if acc is None:
# the fetch method returns null when the account is uninitialized
raise ValueError("account not found")


# convert to a JSON object
obj = acc.to_json()
print(obj)

# load from JSON
acc_from_json = FooAccount.from_json(obj)
```

### Types

```python
# structs

from my_client.types import BarStruct

bar_struct = BarStruct(
some_field="...",
other_field="...",
)

print(bar_struct.to_json())
```

```python
# enums

from my_client.types import baz_enum

tuple_enum = baz_enum.SomeTupleKind((True, False, "some value"))
struct_enum = baz_enum.SomeStructKind({
"field1": "...",
"field2": "...",
})
disc_enum = baz_enum.SomeDiscriminantKind()

print(tuple_enum.toJSON(), struct_enum.toJSON(), disc_enum.toJSON())
```

```python
# types are used as arguments in instruction calls (where needed):
ix = some_instruction({
"some_struct_field": bar_struct,
"some_enum_field": tuple_enum,
# ...
}, {
# accounts
# ...
})

# in case of struct fields, it's also possible to pass them as objects:
ix = some_instruction({
"some_struct_field": {
"some_field": "...",
"other_field": "...",
},
# ...,
}, {
# accounts
# ...
})
```

### Errors

```python
from solana.rpc.core import RPCException
from my_client.errors import from_tx_error
from my_client.errors.custom import SomeCustomError

try:
await provider.send(tx, [payer])
except RPCException as exc:
parsed = from_tx_error(exc)
raise parsed from exc
```

## Program ID

The client generator pulls the program ID from:

- the input IDL
- the `--program-id` flag

If the IDL doesn't contain the program ID then you will need to pass it via the `--program-id` flag.

This program ID is then written into the `program_id.py` file.

25 changes: 25 additions & 0 deletions basics/anchorpy-main/docs/css/custom.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.termynal-comment {
color: #4a968f;
font-style: italic;
display: block;
}

.termy [data-termynal] {
white-space: pre-wrap;
font-size: 14px;
overflow-wrap: break-word;
}

a.external-link::after {
/* \00A0 is a non-breaking space
to make the mark be on the same line as the link
*/
content: "\00A0[↪]";
}

a.internal-link::after {
/* \00A0 is a non-breaking space
to make the mark be on the same line as the link
*/
content: "\00A0↪";
}
6 changes: 6 additions & 0 deletions basics/anchorpy-main/docs/css/mkdocstrings.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* Indentation. */
div.doc-contents:not(.first) {
padding-left: 25px;
border-left: 4px solid rgba(230, 230, 230);
margin-bottom: 80px;
}
Loading