Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
19f7daf
renderers-py init
daog1 May 14, 2025
f33cf11
gen accounts
daog1 May 19, 2025
4fff987
gen types
daog1 May 19, 2025
9a146f7
gen ixs
daog1 May 19, 2025
1e466f0
gen ixs
daog1 May 19, 2025
829c28a
gen ixs
daog1 May 19, 2025
b193379
gen ixs
daog1 May 19, 2025
156c5dc
gen ixs
daog1 May 19, 2025
06d9025
fix gen array pubkey
daog1 May 20, 2025
6248388
fix gen types
daog1 May 20, 2025
146949b
fix gen types
daog1 May 20, 2025
2f17af1
fix gen types
daog1 May 20, 2025
7e3034c
fix gen types
daog1 May 20, 2025
3224762
add string
daog1 May 20, 2025
1570e28
fix args
daog1 May 20, 2025
fe281e5
fmt
daog1 May 21, 2025
2a97245
add gen enum
daog1 May 21, 2025
932f4aa
add gen enum
daog1 May 21, 2025
89ca36f
fix gen enum
daog1 May 21, 2025
f5d586e
add gen option
daog1 May 21, 2025
2fd2b1a
add gen visitFixedSizeType
daog1 May 21, 2025
9f02bf5
add fieldsdecode
daog1 May 22, 2025
29562af
fix types import types
daog1 May 23, 2025
205368c
add enumhelper
daog1 May 23, 2025
923138f
add enumhelper add imports
daog1 May 24, 2025
1b312e5
lint fix
daog1 May 24, 2025
727c589
add enumHelper
daog1 May 24, 2025
639ae33
add to_encodable
daog1 May 24, 2025
14fe724
fix enum struct
daog1 May 25, 2025
2b31571
fix enum
daog1 May 25, 2025
6e1bbae
fix None
daog1 May 25, 2025
a10cf9e
fix line
daog1 May 25, 2025
23260d7
lint fix
daog1 May 26, 2025
fd218cd
add seeds
daog1 May 26, 2025
4b2c884
add seeds
daog1 May 27, 2025
4b348c0
add seeds
daog1 May 27, 2025
3e7475b
gen errors
daog1 May 27, 2025
3b744df
lint fix
daog1 May 27, 2025
bea7efd
fix fromDecode
daog1 May 29, 2025
5c4c33b
fix layout.build encodable
daog1 May 30, 2025
0121705
Code cleanup
daog1 May 30, 2025
e6b5dec
fix enum
daog1 May 30, 2025
446fd14
fix enum
daog1 May 30, 2025
0551fd8
fix SolPubkey
daog1 May 31, 2025
865b6a5
lint:fix
daog1 May 31, 2025
09c862d
del ix RENT
daog1 May 31, 2025
199a45d
add dynamic discriminator
daog1 Jun 2, 2025
72bd669
add test
daog1 Jun 2, 2025
62dcb95
fix b 0x03
daog1 Jun 3, 2025
797bd84
add enum u32
daog1 Jun 3, 2025
4d059ea
fix imports
daog1 Jun 3, 2025
3521958
add Discriminator u64
daog1 Jun 3, 2025
3a0abd3
add e2e shared
daog1 Jun 3, 2025
329b485
fix visitSizePrefixType prefix 64
daog1 Jun 5, 2025
319e669
fix visitSizePrefixType prefix 64
daog1 Jun 5, 2025
f391ace
add throw UNSUPPORTED_NODE
daog1 Jun 5, 2025
8fd4c1c
add test hidden type
daog1 Jun 6, 2025
cf18cfd
add README
daog1 Jun 6, 2025
6824d66
add README
daog1 Jun 6, 2025
5eb0da4
fix extension.py
daog1 Jun 7, 2025
ea5cff6
fix extension.py
daog1 Jun 7, 2025
c9335a6
fix enum
daog1 Jun 7, 2025
1692603
fix enum
daog1 Jun 7, 2025
ebd6901
add types
daog1 Jun 8, 2025
dbf835c
add extension.py
daog1 Jun 9, 2025
5ca8e6d
fix types
daog1 Jun 9, 2025
9cb1c6d
add types
daog1 Jun 10, 2025
b853a8c
add types
daog1 Jun 11, 2025
e135e03
add types f32 f64
daog1 Jun 12, 2025
c2c4213
add types SizePrefix
daog1 Jun 12, 2025
335a9cb
add PROGRAM_ADDRESS
daog1 Jun 12, 2025
0842e4f
console
daog1 Jun 12, 2025
17c0f48
add types test
daog1 Jun 13, 2025
435bc0a
feat(renderers-py): Add support for constant value nodes and improve …
daog1 Jun 14, 2025
601b9f7
feat(solders): Add Pubkey handling and ZeroableOption refactor
daog1 Jun 14, 2025
3235df3
fix types PreOffset
daog1 Jun 14, 2025
c6ac5f4
add types test
daog1 Jun 15, 2025
0d87a71
fix types test
daog1 Jun 16, 2025
5ec346d
fix types test
daog1 Jun 16, 2025
3e1788e
Code cleanup
daog1 Jun 17, 2025
de14fdc
fix conflicts
daog1 Jun 17, 2025
1551eab
fix conflicts
daog1 Jun 17, 2025
d854bd1
fix conflicts
daog1 Jun 17, 2025
66d8755
fix conflicts
daog1 Jun 24, 2025
1349ca4
Code optimization,fix errors
daog1 Jun 24, 2025
0f9ffcb
Remove the dependency on the Solana codec package from the renderers-…
daog1 Jun 25, 2025
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

# dependencies
node_modules
dist
.pnp
.pnp.js

Expand Down
78 changes: 39 additions & 39 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
{
"name": "codama-monorepo",
"private": true,
"scripts": {
"build": "turbo run build --log-order grouped",
"lint": "turbo run lint --log-order grouped",
"lint:fix": "turbo lint:fix --log-order grouped && pnpm prettier --log-level warn --ignore-unknown --write '{.,!packages}/*'",
"test": "turbo run test --log-order grouped",
"publish-packages": "pnpm build && changeset publish"
},
"devDependencies": {
"@changesets/changelog-github": "^0.5.1",
"@changesets/cli": "^2.29.4",
"@codama/internals": "workspace:*",
"@eslint/js": "^9.26.0",
"@eslint/json": "^0.12.0",
"@solana/eslint-config-solana": "^4.0.0",
"@solana/prettier-config-solana": "0.0.5",
"@types/node": "^22",
"@typescript-eslint/eslint-plugin": "^8.32.1",
"@typescript-eslint/parser": "^8.32.0",
"agadoo": "^3.0.0",
"eslint": "^9.26.0",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-sort-keys-fix": "^1.1.2",
"eslint-plugin-typescript-sort-keys": "^3.3.0",
"happy-dom": "^17.4.7",
"prettier": "^3.5.3",
"rimraf": "6.0.1",
"turbo": "^2.5.3",
"tsup": "^8.4.0",
"typescript": "^5.8.3",
"vitest": "^3.1.3",
"zx": "^8.5.4"
},
"engines": {
"node": ">=20.0.0"
},
"packageManager": "[email protected]",
"prettier": "@solana/prettier-config-solana"
"name": "codama-monorepo",
"private": true,
"scripts": {
"build": "turbo run build --log-order grouped",
"lint": "turbo run lint --log-order grouped",
"lint:fix": "turbo lint:fix --log-order grouped && pnpm prettier --log-level warn --ignore-unknown --write '{.,!packages}/*'",
"test": "turbo run test --log-order grouped",
"publish-packages": "pnpm build && changeset publish"
},
"devDependencies": {
"@changesets/changelog-github": "^0.5.1",
"@changesets/cli": "^2.29.5",
"@codama/internals": "workspace:*",
"@eslint/js": "^9.29.0",
"@eslint/json": "^0.12.0",
"@solana/eslint-config-solana": "^4.0.0",
"@solana/prettier-config-solana": "0.0.5",
"@types/node": "^24",
"@typescript-eslint/eslint-plugin": "^8.34.1",
"@typescript-eslint/parser": "^8.34.1",
"agadoo": "^3.0.0",
"eslint": "^9.29.0",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-sort-keys-fix": "^1.1.2",
"eslint-plugin-typescript-sort-keys": "^3.3.0",
"happy-dom": "^18.0.1",
"prettier": "^3.6.0",
"rimraf": "6.0.1",
"turbo": "^2.5.4",
"tsup": "^8.5.0",
"typescript": "^5.8.3",
"vitest": "^3.2.4",
"zx": "^8.5.5"
},
"engines": {
"node": ">=20.0.0"
},
"packageManager": "[email protected]",
"prettier": "@solana/prettier-config-solana"
}
12 changes: 11 additions & 1 deletion packages/nodes-from-anchor/src/v01/InstructionAccountNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,15 @@ export function instructionAccountNodesFromAnchorV01(
return idl.flatMap(account =>
'accounts' in account
? instructionAccountNodesFromAnchorV01(allAccounts, instructionArguments, account.accounts)
: [instructionAccountNodeFromAnchorV01(allAccounts, instructionArguments, account)],
: [instructionAccountNodeFromAnchorV01(allAccounts, instructionArguments, account, idl)],
);
}

export function instructionAccountNodeFromAnchorV01(
allAccounts: AccountNode[],
instructionArguments: InstructionArgumentNode[],
idl: IdlV01InstructionAccount,
parentIdl: IdlV01InstructionAccountItem[],
): InstructionAccountNode {
const isOptional = idl.optional ?? false;
const docs = idl.docs ?? [];
Expand Down Expand Up @@ -133,6 +134,15 @@ export function instructionAccountNodeFromAnchorV01(
programId = getBase58Codec().decode(new Uint8Array(idl.pda.program.value));
break;
}
case 'account': {
const programPath = idl.pda.program.path;
const programNode = parentIdl.find(acc => acc.name == programPath);
if (!(programNode && 'address' in programNode)) {
throw new CodamaError(CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED, { kind });
}
programId = programNode.address;
break;
}
default: {
throw new CodamaError(CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED, { kind });
}
Expand Down
2 changes: 1 addition & 1 deletion packages/renderers-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"main": "./dist/index.node.cjs",
"module": "./dist/index.node.mjs",
"types": "./dist/types/index.d.ts",
"type": "commonjs",
"type": "module",
"files": [
"./dist/templates",
"./dist/types",
Expand Down
206 changes: 206 additions & 0 deletions packages/renderers-py/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
# Codama ➤ Renderers ➤ Python

[![npm][npm-image]][npm-url]
[![npm-downloads][npm-downloads-image]][npm-url]

[npm-downloads-image]: https://img.shields.io/npm/dm/@codama/renderers-rust.svg?style=flat
[npm-image]: https://img.shields.io/npm/v/@codama/renderers-rust.svg?style=flat&label=%40codama%2Frenderers-rust
[npm-url]: https://www.npmjs.com/package/@codama/renderers-rust

This package generates Rust clients from your Codama IDLs.

## Installation

```sh
pnpm install @codama/renderers-py
```

> [!NOTE]
> This package is **not** included in the main [`codama`](../library) package.
>
> However, note that the [`renderers`](../renderers) package re-exports the `renderVisitor` function of this package as `renderPythonVisitor`.
## Usage

Once you have a Codama IDL, you can use the `renderVisitor` of this package to generate Python clients. You will need to provide the base directory where the generated files will be saved and an optional set of options to customize the output.

```ts
// node ./codama.mjs
import { renderVisitor } from '@codama/renderers-py';

const pathToGeneratedFolder = path.join(__dirname, 'clients', 'python', 'src', 'generated');
const options = {}; // See below.
codama.accept(renderVisitor(pathToGeneratedFolder, options));
```

## Generate file directory structure

```
.
├── 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
│ ├── custom.py
│ └── __init__.py
└── program_id.py
```

## Dependencies

```
"borsh-construct>=0.1.0",
"anchorpy>=0.21.0",
"solana>=0.36.6",
"solders>=0.26.0",
```

## Examples

### Instructions

```python
from solders.hash import Hash
from solders.keypair import Keypair
from solders.message import Message
from solders.pubkey import Pubkey
from solders.transaction import Transaction
from solana.rpc.async_api import AsyncClient
from my_client.instructions import some_instruction

# call an instruction
foo_account = Keypair()
async with AsyncClient("http://127.0.0.1:8899") as client:
res = await client.is_connected()
# in real use, fetch this from an RPC
recent_blockhash = (await client.get_latest_blockhash()).value.blockhash

ix = some_instruction({
"foo_param": "...",
"bar_param": "...",
...
},
{
"foo_account": foo_account.pubkey(), # signer
"bar_account": Pubkey("..."),
...
})
msg = Message(instructions=[ix], payer=payer.pubkey())
try:
transaction = Transaction([foo_account], msg, recent_blockhash)
result = (await client.simulate_transaction(transaction))
print(result)
except BaseException as e:
print(f"BaseException failed: {e}")
return None

```

### 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 bazEnum

tupleEnum = bazEnum.SomeTupleKind((True, False, "some value"))
structEnum = bazEnum.SomeStructKind({
"field1": "...",
"field2": "...",
})
discEnum = bazEnum.SomeDiscriminantKind()

print(tupleEnum.toJSON(), structEnum.toJSON(), discEnum.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 Program ID is generated based on the Program address provided in the IDL. If it is not present in the IDL, it needs to be manually filled in.

### Description

The generated code uses the AnchorPy code generation method and some underlying structures.

Support for Codama was added, and some data structures not supported by AnchorPy were included, such as FixedSizeType, SizePrefixType, HiddenSuffixType, HiddenPrefixType, and EnumIndexU32Type.
Loading