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
40 changes: 40 additions & 0 deletions changelog.d/20251106_163012_bobby.lat_decorators.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!--
A new scriv changelog fragment.
Uncomment the section that is right (remove the HTML comment wrapper).
For top level release notes, leave all the headers commented out.
-->

<!--
### Removed
- A bullet item for the Removed category.
-->

### Added

- Added `algopy.public` decorator as an alias of `algopy.arc4.abimethod`.

### Changed

- `@subroutine` decorator is now optional on private contract methods.

<!--
### Deprecated
- A bullet item for the Deprecated category.
-->
<!--
### Fixed
- A bullet item for the Fixed category.
-->
<!--
### Security
- A bullet item for the Security category.
-->
1 change: 1 addition & 0 deletions src/puyapy/awst_build/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
LOGICSIG_DECORATOR_ALIAS = "algopy.logicsig"
ABIMETHOD_DECORATOR = "algopy.arc4.abimethod"
ABIMETHOD_DECORATOR_ALIAS = ABIMETHOD_DECORATOR
PUBLIC_DECORATOR_ALIAS = "algopy.public"
BAREMETHOD_DECORATOR = "algopy.arc4.baremethod"
BAREMETHOD_DECORATOR_ALIAS = BAREMETHOD_DECORATOR
APPROVAL_METHOD = "approval_program"
Expand Down
21 changes: 3 additions & 18 deletions src/puyapy/awst_build/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from puya.parse import SourceLocation
from puya.program_refs import ContractReference
from puya.utils import StableSet, set_add, unique
from puyapy import code_fixes
from puyapy.awst_build import constants, intrinsic_factory, pytypes
from puyapy.awst_build.arc4_decorators import get_arc4_abimethod_data, get_arc4_baremethod_data
from puyapy.awst_build.base_mypy_visitor import BaseMyPyStatementVisitor
Expand Down Expand Up @@ -287,36 +286,22 @@ def visit_function(
func_loc,
)
elif not self.fragment.is_arc4:
if subroutine_dec is None:
logger.error(
f"missing @{constants.SUBROUTINE_HINT_ALIAS} decorator", location=func_loc
)
for invalid_dec in (abimethod_dec, baremethod_dec):
if invalid_dec is not None:
self._error(
f"decorator is only valid in subclasses of {pytypes.ARC4ContractBaseType}",
invalid_dec,
)
else:
if (
num_dec := len(list(filter(None, (subroutine_dec, abimethod_dec, baremethod_dec))))
) != 1:
edits = None
if num_dec == 0:
edits = [
code_fixes.DecorateFunction(constants.SUBROUTINE_HINT),
code_fixes.DecorateFunction(constants.ABIMETHOD_DECORATOR),
code_fixes.DecorateFunction(constants.BAREMETHOD_DECORATOR),
]
if (len(list(filter(None, (subroutine_dec, abimethod_dec, baremethod_dec))))) > 1:
logger.error(
f"ARC-4 contract member functions"
f" (other than __init__ or approval / clear program methods)"
f" must be annotated with exactly one of"
f" must not be annotated with more than one of"
f" @{constants.SUBROUTINE_HINT_ALIAS},"
f" @{constants.ABIMETHOD_DECORATOR_ALIAS},"
f" @{constants.PUBLIC_DECORATOR_ALIAS},"
f" or @{constants.BAREMETHOD_DECORATOR_ALIAS}",
location=func_loc,
edits=edits,
)

if abimethod_dec:
Expand Down
13 changes: 12 additions & 1 deletion src/puyapy/awst_build/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from puya.parse import SourceLocation
from puya.utils import unique
from puyapy.awst_build import pytypes
from puyapy.awst_build.constants import ABIMETHOD_DECORATOR, PUBLIC_DECORATOR_ALIAS
from puyapy.awst_build.context import ASTConversionModuleContext
from puyapy.awst_build.eb.factories import builder_for_type
from puyapy.awst_build.eb.interface import InstanceBuilder, NodeBuilder, TypeBuilder
Expand Down Expand Up @@ -50,6 +51,11 @@ def get_aliased_instance(ref_expr: mypy.nodes.RefExpr) -> mypy.types.Instance |
return None


DECORATOR_ALIAS_MAPPING = {
PUBLIC_DECORATOR_ALIAS: ABIMETHOD_DECORATOR,
}


def get_decorators_by_fullname(
ctx: ASTConversionModuleContext,
decorator: mypy.nodes.Decorator,
Expand All @@ -60,11 +66,16 @@ def get_decorators_by_fullname(
for d in decorator.original_decorators if original else decorator.decorators:
if isinstance(d, mypy.nodes.RefExpr):
full_name = get_unaliased_fullname(d)
result[get_unaliased_fullname(d)] = d
elif isinstance(d, mypy.nodes.CallExpr) and isinstance(d.callee, mypy.nodes.RefExpr):
full_name = get_unaliased_fullname(d.callee)
else:
raise CodeError("Unsupported decorator usage", ctx.node_location(d))

# map alias to canonical name
full_name = DECORATOR_ALIAS_MAPPING.get(full_name, full_name)

if full_name in result:
logger.error("duplicate decorator", location=ctx.node_location(d))
result[full_name] = d
return result

Expand Down
3 changes: 3 additions & 0 deletions stubs/algopy-stubs/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@ from algopy.op import (
Global as Global,
Txn as Txn,
)

# public decorator is an alias for abimethod to provide a cleaner API
public = arc4.abimethod
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will need a stubs version bump.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was already bumped for fixed bytes which is unreleased, so another bump isn't necessary?

All tho worth noting the fixed bytes bump was incorrect, it should have been 3.2.0 not 3.2.1 So could fix that in this PR, or have another PR to fix that

2 changes: 1 addition & 1 deletion stubs/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ name = "algorand-python"
# When updating this value, if it is a major/minor change, make sure to update:
# src/puyapy/parse.py:MAX_SUPPORTED_ALGOPY_VERSION_EX
# For more info see stubs/README.md#versioning
version = "3.2.1"
version = "3.2.0"
description = "API for writing Algorand Python Smart contracts"
authors = [{ name = "Algorand Foundation", email = "[email protected]" }]
readme = "README.md"
Expand Down
2 changes: 1 addition & 1 deletion stubs/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions test_cases/arc4_contract/contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from algopy import ARC4Contract, UInt64, public


class TestContract(ARC4Contract):
@public
def test_method(self, value: UInt64) -> UInt64:
"""Test method using @public decorator"""
return value + UInt64(1)
Loading
Loading