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
7 changes: 3 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ test:
uv run --all-extras 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 ../../.. && uv run anchorpy client-gen tests/idls/clientgen_example_program.json tests/client_gen/example_program_gen --program-id 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8 --pdas
uv run anchorpy client-gen tests/idls/basic_2.json examples/client-gen/basic_2 --program-id 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8
uv run anchorpy client-gen tests/idls/tictactoe.json examples/client-gen/tictactoe --program-id 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8
uv run anchorpy client-gen tests/idls/spl_token.json tests/client_gen/token --program-id TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
cd tests/client_gen/example-program/ && anchor idl parse -f programs/example-program/src/lib.rs -o ../../idls/clientgen_example_program.json && cd ../../.. && uv run anchorpy client-gen tests/idls/clientgen_example_program.json tests/client_gen/example_program_gen --pdas
uv run anchorpy client-gen tests/idls/basic_2.json examples/client-gen/basic_2
uv run anchorpy client-gen tests/idls/tictactoe.json examples/client-gen/tictactoe

lint:
uv run ruff src tests
Expand Down
13 changes: 2 additions & 11 deletions docs/clientgen/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ Arguments:
OUT Output directory. [required]

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

```
Expand Down Expand Up @@ -88,7 +87,7 @@ from my_client.instructions import some_instruction
# call an instruction
foo_account = Keypair()
# in real use, fetch this from an RPC
recent_blockhash = Hash.default()
recent_blockhash = Hash.default()

ix = some_instruction({
"foo_param": "...",
Expand Down Expand Up @@ -200,12 +199,4 @@ except RPCException as 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.

The client generator pulls the program ID from the input IDL.
9 changes: 6 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[project]
name = "anchorpy"
version = "0.21.0"
version = "0.32.1"
description = "The Python Anchor client."
authors = [{ name = "kevinheavey", email = "kevinheavey123@gmail.com" }]
requires-python = "~=3.9"
requires-python = ">=3.9,<3.14"
readme = "README.md"
dependencies = [
"construct-typing>=0.5.1,<0.6",
Expand All @@ -13,8 +13,8 @@ dependencies = [
"toolz>=0.11.2,<0.12",
"pyheck>=0.1.4,<0.2",
"based58>=0.1.1,<0.2",
"anchorpy-core>=0.2.0,<0.3",
"toml>=0.10.2,<0.11",
"anchorpy-idl @ git+https://github.com/plocca-inc/anchorpy-idl.git@anchor-0.32.1",
]

[project.optional-dependencies]
Expand Down Expand Up @@ -124,3 +124,6 @@ convention = "google"

[tool.pyright]
reportMissingModuleSource = false

[tool.hatch.metadata]
allow-direct-references = true
4 changes: 2 additions & 2 deletions src/anchorpy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""The Python Anchor client."""
from contextlib import suppress as __suppress

from anchorpy_core.idl import Idl
from anchorpy_idl import Idl

from anchorpy import error, utils
from anchorpy.coder.coder import AccountsCoder, Coder, EventCoder, InstructionCoder
Expand Down Expand Up @@ -65,4 +65,4 @@
else __all_core
)

__version__ = "0.21.0"
__version__ = "0.32.1"
22 changes: 2 additions & 20 deletions src/anchorpy/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Optional, cast

import typer
from anchorpy_core.idl import Idl
from anchorpy_idl import Idl
from IPython import embed

from anchorpy import create_workspace
Expand Down Expand Up @@ -98,36 +98,18 @@ def init(
def client_gen(
idl: Path = typer.Argument(..., help="Anchor IDL file path"),
out: Path = typer.Argument(..., help="Output directory."),
program_id: Optional[str] = typer.Option(
None, help="Optional program ID to be included in the code"
),
pdas: bool = typer.Option(
False, "--pdas", help="Auto-generate PDAs where possible."
),
):
"""Generate Python client code from the specified anchor IDL."""
idl_obj = Idl.from_json(idl.read_text())
if program_id is None:
idl_metadata = idl_obj.metadata
address_from_idl = (
idl_metadata["address"] if isinstance(idl_metadata, dict) else None
)
if address_from_idl is None:
typer.echo(
"No program ID found in IDL. Use the --program-id "
"option to set it manually."
)
raise typer.Exit(code=1)
else:
program_id_to_use = cast(str, address_from_idl)
else:
program_id_to_use = program_id

typer.echo("generating package...")
out.mkdir(exist_ok=True)
(out / "__init__.py").touch()
typer.echo("generating program_id.py...")
gen_program_id(program_id_to_use, out)
gen_program_id(idl_obj.address, out)
typer.echo("generating errors.py...")
gen_errors(idl_obj, out)
typer.echo("generating instructions...")
Expand Down
18 changes: 11 additions & 7 deletions src/anchorpy/clientgen/accounts.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from pathlib import Path
from typing import cast

from anchorpy_core.idl import (
from anchorpy_idl import (
Idl,
IdlField,
IdlTypeDefinition,
IdlTypeDefinitionTyStruct,
IdlTypeDef,
IdlTypeDefStruct,
)
from autoflake import fix_code
from black import FileMode, format_str
Expand All @@ -31,6 +31,7 @@
_idl_type_to_json_type,
_json_interface_name,
_layout_for_type,
_partition_idl_types,
_py_type_from_idl,
_sanitize,
)
Expand Down Expand Up @@ -83,16 +84,18 @@ def gen_index_code(idl: Idl) -> str:


def gen_accounts_code(idl: Idl, accounts_dir: Path) -> dict[Path, str]:
account_types, _ = _partition_idl_types(idl)
account_type_map = {t.name: t for t in account_types}
res = {}
for acc in idl.accounts:
filename = f"{_sanitize(snake(acc.name))}.py"
path = accounts_dir / filename
code = gen_account_code(acc, idl)
code = gen_account_code(account_type_map[acc.name], idl)
res[path] = code
return res


def gen_account_code(acc: IdlTypeDefinition, idl: Idl) -> str:
def gen_account_code(acc: IdlTypeDef, idl: Idl) -> str:
base_imports = [
Import("typing"),
FromImport("dataclasses", ["dataclass"]),
Expand All @@ -109,12 +112,13 @@ def gen_account_code(acc: IdlTypeDefinition, idl: Idl) -> str:
),
FromImport("..program_id", ["PROGRAM_ID"]),
]
_, user_types = _partition_idl_types(idl)
imports = (
[*base_imports, FromImport("..", ["types"])] if idl.types else base_imports
[*base_imports, FromImport("..", ["types"])] if user_types else base_imports
)
fields_interface_params: list[TypedParam] = []
json_interface_params: list[TypedParam] = []
ty = cast(IdlTypeDefinitionTyStruct, acc.ty)
ty = cast(IdlTypeDefStruct, acc.ty)
fields = ty.fields
name = _sanitize(acc.name)
json_interface_name = _json_interface_name(name)
Expand Down
Loading