nickthelegend/website-dataset huggingface dataset:
Back to top
View this page
Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
Algorand Python
¶
Algorand Python is a partial implementation of the Python programming language that runs on the AVM. It includes a statically typed framework for development of Algorand smart contracts and logic signatures, with Pythonic interfaces to underlying AVM functionality that works with standard Python tooling.
Algorand Python is compiled for execution on the AVM by PuyaPy, an optimising compiler that ensures the resulting AVM bytecode execution semantics that match the given Python code. PuyaPy produces output that is directly compatible with
AlgoKit typed clients
to make deployment and calling easy.
Quick start
¶
The easiest way to use Algorand Python is to instantiate a template with AlgoKit via
algokit
init
-t
python
. This will give you a full development environment with intellisense, linting, automatic formatting, breakpoint debugging, deployment and CI/CD.
Alternatively, if you want to start from scratch you can do the following:
Ensure you have Python 3.12+
Install
AlgoKit CLI
Check you can run the compiler:
algokit
compile
py
-h
Install Algorand Python into your project
poetry
add
algorand-python
Create a contract in a (e.g.)
contract.py
file:
from
algopy
import
ARC4Contract
,
arc4
class
HelloWorldContract
(
ARC4Contract
):
@arc4
.
abimethod
def
hello
(
self
,
name
:
arc4
.
String
)
->
arc4
.
String
:
return
"Hello, "
+
name
Compile the contract:
algokit
compile
py
contract.py
You should now have
HelloWorldContract.approval.teal
and
HelloWorldContract.clear.teal
on the file system!
We generally recommend using ARC-32 and
generated typed clients
to have the most optimal deployment and consumption experience; to do this you need to ask PuyaPy to output an ARC-32 compatible app spec file:
algokit
compile
py
contract.py
--output-arc32
--no-output-teal
You should now have
HelloWorldContract.arc32.json
, which can be generated into a client e.g. using AlgoKit CLI:
algokit
generate
client
HelloWorldContract.arc32.json
--output
client.py
From here you can dive into the
examples
or look at the
documentation
.
Programming with Algorand Python
¶
To get started developing with Algorand Python, please take a look at the
Language Guide
.
Using the PuyaPy compiler
¶
To see detailed guidance for using the PuyaPy compiler, please take a look at the
Compiler guide
.
Next
Language Guide
Copyright © 2024, Algorand Foundation
Made with
Sphinx
and
@pradyunsg
's
Furo
Back to top
View this page
Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
Control flow structures
¶
Control flow in Algorand Python is similar to standard Python control flow, with support for if statements, while loops, for loops, and match statements.
If statements
¶
If statements work the same as Python. The conditions must be an expression that evaluates to bool, which can include a
String or Uint64
among others.
if
condition
:
# block of code to execute if condition is True
elif
condition2
:
# block of code to execute if condition is False and condition2 is True
else
:
# block of code to execute if condition and condition2 are both False
See full example
.
Ternary conditions
¶
Ternary conditions work the same as Python. The condition must be an expression that evaluates to bool, which can include a
String or Uint64
among others.
value1
=
UInt64
(
5
)
value2
=
String
(
">6"
)
if
value1
>
6
else
String
(
"<=6"
)
While loops
¶
While loops work the same as Python. The condition must be an expression that evaluates to bool, which can include a
String or Uint64
among others.
You can use
break
and
continue
.
while
condition
:
# block of code to execute if condition is True
See full example
.
For Loops
¶
For loops are used to iterate over sequences, ranges and
ARC-4 arrays
. They work the same as Python.
Algorand Python provides functions like
uenumerate
and
urange
to facilitate creating sequences and ranges; in-built Python
reversed
method works with these.
uenumerate
is similar to Python’s built-in enumerate function, but for UInt64 numbers; it allows you to loop over a sequence and have an automatic counter.
urange
is a function that generates a sequence of Uint64 numbers, which you can iterate over.
reversed
returns a reversed iterator of a sequence.
Here is an example of how you can use these functions in a contract:
test_array
=
arc4
.
StaticArray
(
arc4
.
UInt8
(),
arc4
.
UInt8
(),
arc4
.
UInt8
(),
arc4
.
UInt8
())
# urange: reversed items, forward index
for
index
,
item
in
uenumerate
(
reversed
(
urange
(
4
))):
test_array
[
index
]
=
arc4
.
UInt8
(
item
)
assert
test_array
.
bytes
==
Bytes
.
from_hex
(
"03020100"
)
See full
examples
.
Match Statements
¶
Match statements work the same as Python and work for […]
match
value
:
case
pattern1
:
# block of code to execute if pattern1 matches
case
pattern2
:
# block of code to execute if pattern2 matches
case
_
:
# Fallback
Note: Captures and patterns are not supported. Currently, there is only support for basic case/switch functionality; pattern matching and guard clauses are not currently supported.
See full example
.
Next
Module level constructs
Previous
Types
Copyright © 2024, Algorand Foundation
Made with
Sphinx
and
@pradyunsg
's
Furo
Back to top
View this page
Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
Module level constructs
¶
You can write compile-time constant code at a module level and then use them in place of
Python built-in literal types
.
For a full example of what syntax is currently possible see the
test case example
.
Module constants
¶
Module constants are compile-time constant, and can contain
bool
,
int
,
str
and
bytes
.
You can use fstrings and other compile-time constant values in module constants too.
For example:
from
algopy
import
UInt64
,
subroutine
SCALE
=
100000
SCALED_PI
=
314159
@subroutine
def
circle_area
(
radius
:
UInt64
)
->
UInt64
:
scaled_result
=
SCALED_PI
*
radius
**
2
result
=
scaled_result
//
SCALE
return
result
@subroutine
def
circle_area_100
()
->
UInt64
:
return
circle_area
(
UInt64
(
100
))
If statements
¶
You can use if statements with compile-time constants in module constants.
For example:
FOO
=
42
if
FOO
>
12
:
BAR
=
123
else
:
BAR
=
456
Integer math
¶
Module constants can also be defined using common integer expressions.
For example:
SEVEN
=
7
TEN
=
7
+
3
FORTY_NINE
=
7
**
2
Strings
¶
Module
str
constants can use f-string formatting and other common string expressions.
For example:
NAME
=
"There"
MY_FORMATTED_STRING
=
f
"Hello
{
NAME
}
"
# Hello There
PADDED
=
f
"
{
123
:
05
}
"
# "00123"
DUPLICATED
=
"5"
*
3
# "555"
Type aliases
¶
You can create type aliases to make your contract terser and more expressive.
For example:
import
typing
from
algopy
import
arc4
VoteIndexArray
:
typing
.
TypeAlias
=
arc4
.
DynamicArray
[
arc4
.
UInt8
]
Row
:
typing
.
TypeAlias
=
arc4
.
StaticArray
[
arc4
.
UInt8
,
typing
.
Literal
[
3
]]
Game
:
typing
.
TypeAlias
=
arc4
.
StaticArray
[
Row
,
typing
.
Literal
[
3
]]
Move
:
typing
.
TypeAlias
=
tuple
[
arc4
.
UInt64
,
arc4
.
UInt64
]
Bytes32
:
typing
.
TypeAlias
=
arc4
.
StaticArray
[
arc4
.
Byte
,
typing
.
Literal
[
32
]]
Proof
:
typing
.
TypeAlias
=
arc4
.
DynamicArray
[
Bytes32
]
Next
Python builtins
Previous
Control flow structures
Copyright © 2024, Algorand Foundation
Made with
Sphinx
and
@pradyunsg
's
Furo
Back to top
View this page
Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
Python builtins
¶
Some common python builtins have equivalent
algopy
versions, that use an
UInt64
instead of a native
int
.
len
¶
The
len()
builtin is not supported, instead
algopy
types that have a length have a
.length
property of type
UInt64
. This is primarily
due to
len()
always returning
int
and the CPython implementation enforcing that it returns
exactly
int
.
range
¶
The
range()
builtin has an equivalent
algopy.urange
this behaves the same as the python builtin except that it returns
an iteration of
UInt64
values instead of
int
.
enumerate
¶
The
enumerate()
builtin has an equivalent
algopy.uenumerate
this behaves the same as the python builtin except that it returns
an iteration of
UInt64
index values and the corresponding item.
reversed
¶
The
reversed()
builtin is supported when iterating within a
for
loop and behaves the same as the python builtin.
types
¶
See
here
Next
Error handling and assertions
Previous
Module level constructs
Copyright © 2024, Algorand Foundation
Made with
Sphinx
and
@pradyunsg
's
Furo
Back to top
View this page
Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
Error handling and assertions
¶
In Algorand Python, error handling and assertions play a crucial role in ensuring the correctness and robustness of smart contracts.
Assertions
¶
Assertions allow you to immediately fail a smart contract if a
Boolean statement or value
evaluates to
False
. If an assertion fails, it immediately stops the execution of the contract and marks the call as a failure.
In Algorand Python, you can use the Python built-in
assert
statement to make assertions in your code.
For example:
@subroutine
def
set_value
(
value
:
UInt64
):
assert
value
>
4
,
"Value must be > 4"
Assertion error handling
¶
The (optional) string value provided with an assertion, if provided, will be added as a TEAL comment on the end of the assertion line. This works in concert with default AlgoKit Utils app client behaviour to show a TEAL stack trace of an error and thus show the error message to the caller (when source maps have been loaded).
Explicit failure
¶
For scenarios where you need to fail a contract explicitly, you can use
the
op.err()
operation. This operation causes the TEAL program to immediately
and unconditionally fail.
Alternatively
op.exit(0)
will achieve the same result. A non-zero value will
do the opposite and immediately succeed.
Exception handling
¶
The AVM doesn’t provide error trapping semantics so it’s not possible to implement
raise
and
catch
.
For more details see
Unsupported Python features
.
Next
Storing data on-chain
Previous
Python builtins
Copyright © 2024, Algorand Foundation
Made with
Sphinx
and
@pradyunsg
's
Furo
Back to top
View this page
Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
Logging
¶
Algorand Python provides a
log
method
that allows you to emit debugging and event information as well as return values from your contracts to the caller.
This
log
method is a superset of the
AVM
log
method
that adds extra functionality:
You can log multiple items rather than a single item
Items are concatenated together with an optional separator (which defaults to:
""
)
Items are automatically converted to bytes for you
Support for:
int
literals / module variables (encoded as raw bytes, not ASCII)
UInt64
values (encoded as raw bytes, not ASCII)
str
literals / module variables (encoded as UTF-8)
bytes
literals / module variables (encoded as is)
Bytes
values (encoded as is)
BytesBacked
values, which includes
String
,
BigUInt
,
Account
and all of the
ARC-4 types
(encoded as their underlying bytes values)
Logged values are
available to the calling client
and attached to the transaction record stored on the blockchain ledger.
If you want to emit ARC-28 events in the logs then there is a
purpose-built function for that
.
Here’s an example contract that uses the log method in various ways:
from
algopy
import
BigUInt
,
Bytes
,
Contract
,
log
,
op
class
MyContract
(
Contract
):
def
approval_program
(
self
)
->
bool
:
log
(
0
)
log
(
b
"1"
)
log
(
"2"
)
log
(
op
.
Txn
.
num_app_args
+
3
)
log
(
Bytes
(
b
"4"
)
if
op
.
Txn
.
num_app_args
else
Bytes
())
log
(
b
"5"
,
6
,
op
.
Txn
.
num_app_args
+
7
,
BigUInt
(
8
),
Bytes
(
b
"9"
)
if
op
.
Txn
.
num_app_args
else
Bytes
(),
sep
=
"_"
,
)
return
True
def
clear_state_program
(
self
)
->
bool
:
return
True
Next
Transactions
Previous
Storing data on-chain
Copyright © 2024, Algorand Foundation
Made with
Sphinx
and
@pradyunsg
's
Furo
Back to top
View this page
Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
AVM operations
¶
Algorand Python allows you to do express
every op code the AVM has available
apart from ops that manipulate the stack (to avoid conflicts with the compiler), and
log
(to avoid confusion with the superior
Algorand Python log function
). These ops are exposed via the
algopy.op
submodule.
We generally recommend importing this entire submodule so you can use intellisense to discover the available methods:
from
algopy
import
UInt64
,
op
,
subroutine
@subroutine
def
sqrt_16
()
->
UInt64
:
return
op
.
sqrt
(
16
)
All ops are typed using Algorand Python types and have correct static type representations.
Many ops have higher-order functionality that Algorand Python exposes and would limit the need to reach for the underlying ops. For instance, there is first-class support for local and global storage so there is little need to use the likes of
app_local_get
et. al. But they are still exposed just in case you want to do something that Algorand Python’s abstractions don’t support.
Txn
¶
The
Txn
opcodes are so commonly used they have been exposed directly in the
algopy
module and can be easily imported to make it terser to access:
from
algopy
import
subroutine
,
Txn
@subroutine
def
has_no_app_args
()
->
bool
:
return
Txn
.
num_app_args
==
0
Global
¶
The
Global
opcodes are so commonly used they have been exposed directly in the
algopy
module and can be easily imported to make it terser to access:
from
algopy
import
subroutine
,
Global
,
Txn
@subroutine
def
only_allow_creator
()
->
None
:
assert
Txn
.
sender
==
Global
.
creator_address
,
"Only the contract creator can perform this operation"
Next
Opcode budgets
Previous
Transactions
Copyright © 2024, Algorand Foundation
Made with
Sphinx
and
@pradyunsg
's
Furo
Back to top
View this page
Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
Opcode budgets
¶
Algorand Python provides a helper method for increasing the
available opcode budget
, see
algopy.ensure_budget
.
Next
ARC-4: Application Binary Interface
Previous
AVM operations
Copyright © 2024, Algorand Foundation
Made with
Sphinx
and
@pradyunsg
's
Furo
Back to top
View this page
Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
Compiling to AVM bytecode
¶
The PuyaPy compiler can compile Algorand Python smart contracts directly into AVM bytecode.
Once compiled, this bytecode can be utilized to construct AVM Application Call transactions both on and off chain.
Outputting AVM bytecode from CLI
¶
The
--output-bytecode
option can be used to generate
.bin
files for smart contracts and logic signatures, producing an approval and clear program for each smart contract.
Obtaining bytecode within other contracts
¶
The
compile_contract
function takes an Algorand Python smart contract class and returns a
CompiledContract
,
The global state, local state and program pages allocation parameters are derived from the contract by default, but can be overridden.
This compiled contract can then be used to create an
algopy.itxn.ApplicationCall
transaction or used with the
ARC4
functions.
The
compile_logicsig
takes an Algorand Python logic signature and returns a
CompiledLogicSig
, which can be used to
verify if a transaction has been signed by a particular logic signature.
Template variables
¶
Algorand Python supports defining
algopy.TemplateVar
variables that can be substituted during compilation.
For example, the following contract has
UInt64
and
Bytes
template variables.
templated_contract.py
¶
from
algopy
import
ARC4Contract
,
Bytes
,
TemplateVar
,
UInt64
,
arc4
class
TemplatedContract
(
ARC4Contract
):
@arc4
.
abimethod
def
my_method
(
self
)
->
UInt64
:
return
TemplateVar
[
UInt64
](
"SOME_UINT"
)
@arc4
.
abimethod
def
my_other_method
(
self
)
->
Bytes
:
return
TemplateVar
[
Bytes
](
"SOME_BYTES"
)
When compiling to bytecode, the values for these template variables must be provided. These values can be provided via the CLI,
or through the
template_vars
parameter of the
compile_contract
and
compile_logicsig
functions.
CLI
¶
The
--template-var
option can be used to
define
each variable.
For example to provide the values for the above example contract the following command could be used
puyapy
--template-var
SOME_UINT=123
--template-var
SOME_BYTES=0xABCD
templated_contract.py
Within other contracts
¶
The functions
compile_contract
and
compile_logicsig
both have an optional
template_vars
parameter
which can be used to define template variables. Variables defined in this manner take priority over variables defined on the CLI.
from
algopy
import
Bytes
,
UInt64
,
arc4
,
compile_contract
,
subroutine
from
templated_contract
import
TemplatedContract
@subroutine
def
create_templated_contract
()
->
None
:
compiled
=
compile_contract
(
TemplatedContract
,
global_uints
=
2
,
# customize allocated global uints
template_vars
=
{
# provide template vars
"SOME_UINT"
:
UInt64
(
123
),
"SOME_BYTES"
:
Bytes
(
b
"
\xAB\xCD
"
)
},
)
arc4
.
arc4_create
(
TemplatedContract
,
compiled
=
compiled
)
Next
Unsupported Python features
Previous
Calling other applications
Copyright © 2024, Algorand Foundation
Made with
Sphinx
and
@pradyunsg
's
Furo
Back to top
View this page
Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
Unsupported Python features
¶
raise, try/except/finally
¶
Exception raising and exception handling constructs are not supported.
Supporting user exceptions would be costly to implement in terms of op codes.
Furthermore, AVM errors and exceptions are not “catch-able”, they immediately terminate the
program.
Therefore, there is very little to no benefit of supporting exceptions and exception handling.
The preferred method of raising an error that terminates is through the use of
assert statements
.
with
¶
Context managers are redundant without exception handling support.
async
¶
The AVM is not just single threaded, but all operations are effectively “blocking”, rendering
asynchronous programming effectively useless.
closures & lambdas
¶
Without the support of function pointers, or other methods of invoking an arbitrary function,
it’s not possible to return a function as a closure.
Nested functions/lambdas as a means of repeating common operations within a given function may be
supported in the future.
global keyword
¶
Module level values are only allowed to be
constants
. No
rebinding of module constants is allowed. It’s not clear what the meaning here would be, since
there’s no real arbitrary means of storing state without associating it with a particular contract.
If you do have need of such a thing, take a look at
gload_bytes
or
gload_uint64
if the contracts are within the same transaction,
otherwise
AppGlobal.get_ex_bytes
and
AppGlobal.get_ex_uint64
.
Inheritance (outside of contract classes)
¶
Polymorphism is also impossible to support without function pointers, so data classes (such as
arc4.Struct
) don’t currently allow for inheritance. Member functions there
are not supported because we’re not sure yet whether it’s better to not have inheritance but allow
functions on data classes, or to allow inheritance and disallow member functions.
Contract inheritance is a special case, since each concrete contract is compiled separately, true
polymorphism isn’t required as all references can be resolved at compile time.
Next
Principles & Background
Previous
Compiling to AVM bytecode
Copyright © 2024, Algorand Foundation
Made with
Sphinx
and
@pradyunsg
's
Furo
Back to top
View this page
Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
API Reference
¶
algopy
Package Contents
Classes
Functions
Data
API
ARC4Contract
Account
Application
Asset
BigUInt
Box
BoxMap
BoxRef
Bytes
BytesBacked
CompiledContract
CompiledLogicSig
Contract
Global
GlobalState
LocalState
LogicSig
OnCompleteAction
OpUpFeeSource
StateTotals
String
TemplateVar
TransactionType
Txn
UInt64
compile_contract()
compile_logicsig()
ensure_budget()
log()
logicsig()
subroutine()
uenumerate
urange
algopy.arc4
Module Contents
Classes
Functions
Data
API
ARC4Client
ARC4Contract
Address
BigUFixedNxM
BigUIntN
Bool
Byte
DynamicArray
DynamicBytes
StaticArray
String
Struct
Tuple
UFixedNxM
UInt128
UInt16
UInt256
UInt32
UInt512
UInt64
UInt8
UIntN
abi_call
abimethod()
arc4_create()
arc4_signature()
arc4_update()
baremethod()
emit()
algopy.gtxn
Module Contents
Classes
API
ApplicationCallTransaction
AssetConfigTransaction
AssetFreezeTransaction
AssetTransferTransaction
KeyRegistrationTransaction
PaymentTransaction
Transaction
TransactionBase
algopy.itxn
Module Contents
Classes
Functions
API
ApplicationCall
ApplicationCallInnerTransaction
AssetConfig
AssetConfigInnerTransaction
AssetFreeze
AssetFreezeInnerTransaction
AssetTransfer
AssetTransferInnerTransaction
InnerTransaction
InnerTransactionResult
KeyRegistration
KeyRegistrationInnerTransaction
Payment
PaymentInnerTransaction
submit_txns()
algopy.op
Module Contents
Classes
Functions
API
AcctParamsGet
AppGlobal
AppLocal
AppParamsGet
AssetHoldingGet
AssetParamsGet
Base64
Block
Box
EC
ECDSA
EllipticCurve
GITxn
GTxn
Global
ITxn
ITxnCreate
JsonRef
MiMCConfigurations
Scratch
Txn
VoterParamsGet
VrfVerify
addw()
app_opted_in()
arg()
balance()
base64_decode()
bitlen()
bsqrt()
btoi()
bzero()
concat()
divmodw()
divw()
ecdsa_pk_decompress()
ecdsa_pk_recover()
ecdsa_verify()
ed25519verify()
ed25519verify_bare()
err()
exit()
exp()
expw()
extract()
extract_uint16()
extract_uint32()
extract_uint64()
falcon_verify()
gaid()
getbit()
getbyte()
gload_bytes()
gload_uint64()
itob()
keccak256()
mimc()
min_balance()
mulw()
online_stake()
replace()
select_bytes()
select_uint64()
setbit_bytes()
setbit_uint64()
setbyte()
sha256()
sha3_256()
sha512_256()
shl()
shr()
sqrt()
substring()
sumhash512()
vrf_verify()
Next
algopy
Previous
Principles & Background
Copyright © 2024, Algorand Foundation
Made with
Sphinx
and
@pradyunsg
's
Furo
Back to top
View this page
Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
Algorand Python Testing
¶
algorand-python-testing
is a companion package to
Algorand Python
that enables efficient unit testing of Algorand Python smart contracts in an offline environment. This package emulates key AVM behaviors without requiring a network connection, offering fast and reliable testing capabilities with a familiar Pythonic interface.
The
algorand-python-testing
package provides:
A simple interface for fast and reliable unit testing
An offline testing environment that simulates core AVM functionality
A familiar Pythonic experience, compatible with testing frameworks like
pytest
,
unittest
, and
hypothesis
Quick Start
¶
To get started refer to the
official documentation
.
Next
Breakpoint debugging
Previous
PuyaPy compiler
Copyright © 2024, Algorand Foundation
Made with
Sphinx
and
@pradyunsg
's
Furo
Back to top
View this page
Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
Breakpoint debugging
¶
The AlgoKit AVM VS Code Debugger extension enables line-by-line debugging of Algorand Python smart contracts that are executed on the AVM. It provides a seamless debugging experience by leveraging AVM simulate traces and source maps.
Quick Start
¶
For detailed setup instructions, features, and advanced usage, please refer to the
official repository
.
Previous
Algorand Python Testing
Copyright © 2024, Algorand Foundation
Made with
Sphinx
and
@pradyunsg
's
Furo