Skip to content

Python Types

LUMOS generates Python dataclasses with borsh-construct for Borsh serialization.

Terminal window
pip install borsh-construct
LUMOS TypePython TypeBorsh Schema
u8intU8
u16intU16
u32intU32
u64intU64
u128intU128
i8intI8
i16intI16
i32intI32
i64intI64
i128intI128
boolboolBool
StringstrString
PublicKeybytesBytes(32)
SignaturebytesBytes(64)
Vec<T>List[T]Vec(T)
Option<T>Optional[T]Option(T)
[T; N]List[T]Bytes(N) or Array(T, N)

#[solana]
struct PlayerAccount {
wallet: PublicKey,
level: u16,
experience: u64,
username: String,
guild: Option<PublicKey>,
inventory: [u8],
}
"""
Generated by LUMOS - Do not edit manually
Schema: player_account.lumos
"""
from dataclasses import dataclass
from typing import Optional, List
from borsh_construct import CStruct, U8, U16, U64, String, Vec, Option, Bytes
@dataclass
class PlayerAccount:
"""PlayerAccount - Generated from LUMOS schema"""
wallet: bytes # PublicKey (32 bytes)
level: int # u16
experience: int # u64
username: str # String
guild: Optional[bytes] # Option<PublicKey>
inventory: List[int] # Vec<u8>
# Borsh schema for serialization
PlayerAccountSchema = CStruct(
"wallet" / Bytes(32),
"level" / U16,
"experience" / U64,
"username" / String,
"guild" / Option(Bytes(32)),
"inventory" / Vec(U8),
)

from player_schema import PlayerAccount, PlayerAccountSchema
# Create an account
account = PlayerAccount(
wallet=bytes.fromhex("11" * 32), # 32-byte public key
level=42,
experience=150000,
username="CryptoGamer",
guild=None, # No guild
inventory=[1, 2, 3, 4, 5],
)
# Serialize to bytes
serialized = PlayerAccountSchema.build(account.__dict__)
print(f"Serialized: {serialized.hex()}")
# Deserialize from bytes
data = bytes.fromhex("...") # Borsh-encoded data
parsed = PlayerAccountSchema.parse(data)
account = PlayerAccount(
wallet=parsed.wallet,
level=parsed.level,
experience=parsed.experience,
username=parsed.username,
guild=parsed.guild,
inventory=list(parsed.inventory),
)
print(f"Level: {account.level}")
print(f"XP: {account.experience}")

from enum import IntEnum
class GameStatus(IntEnum):
"""GameStatus enum"""
Active = 0
Paused = 1
Ended = 2
GameStatusSchema = U8 # Simple discriminant
from dataclasses import dataclass
from typing import Union
@dataclass
class Transfer:
"""Transfer variant"""
recipient: bytes
amount: int
@dataclass
class Stake:
"""Stake variant"""
validator: bytes
amount: int
# Union type for enum
Instruction = Union[Transfer, Stake]

# Convert to/from base58
import base58
def pubkey_to_base58(pubkey: bytes) -> str:
return base58.b58encode(pubkey).decode()
def base58_to_pubkey(s: str) -> bytes:
return base58.b58decode(s)

Python’s int handles arbitrary precision, so no overflow concerns:

# Safe in Python
max_u64 = 18446744073709551615
max_u128 = 340282366920938463463374607431768211455
# Both work correctly
account.balance = max_u64
account.total_supply = max_u128
# Check optional fields before use
if account.guild is not None:
print(f"Guild: {pubkey_to_base58(account.guild)}")
else:
print("No guild")

from solana.rpc.api import Client
from solana.publickey import PublicKey
client = Client("https://api.devnet.solana.com")
# Fetch account
account_pubkey = PublicKey("...")
response = client.get_account_info(account_pubkey)
if response["result"]["value"]:
data = base64.b64decode(response["result"]["value"]["data"][0])
# Skip 8-byte discriminator for Anchor accounts
account_data = data[8:]
parsed = PlayerAccountSchema.parse(account_data)