Skip to content

Commit d3dcfc1

Browse files
authored
refactor: decouples reference type attribute names (#237)
* fix: align reference type attribute names with wire format using metadata - Add wire() metadata to BoxReference, HoldingReference, and LocalsReference dataclasses to specify API wire format field names (app, asset, account, name) - Use Pythonic field names in code (app_id, asset_id, address) for better API consistency - Add _decode_address_field helper to handle address decoding from wire format - Update composer_resources.py and transaction_composer.py to use new attribute names This fixes attribute mismatches where the API wire format uses short names (app, asset, account) but our dataclasses should use descriptive Python naming conventions (app_id, asset_id, address). * refactor: align against latest specs with plural num_* keys aligning with transact naming * chore: temporarily change branch to point to pr on oas generator with new specs * chore: set schemas branch back to main
1 parent ed9a947 commit d3dcfc1

File tree

25 files changed

+911
-901
lines changed

25 files changed

+911
-901
lines changed

api/oas-generator/src/oas_generator/builder.py

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ class TypeInfo:
2929
is_bytes: bool = False
3030
list_inner_is_bytes: bool = False
3131
is_signed_transaction: bool = False
32+
is_box_reference: bool = False
33+
is_locals_reference: bool = False
34+
is_holding_reference: bool = False
3235
needs_datetime: bool = False
3336
imports: set[str] = field(default_factory=set)
3437

@@ -116,6 +119,12 @@ def _classify(self, schema: ctx.RawSchema) -> str:
116119
return "enum"
117120
if schema.get("x-algokit-signed-txn"):
118121
return "signed"
122+
if schema.get("x-algokit-box-reference"):
123+
return "box_reference"
124+
if schema.get("x-algokit-locals-reference"):
125+
return "locals_reference"
126+
if schema.get("x-algokit-holding-reference"):
127+
return "holding_reference"
119128
if schema.get("type") == "object" or schema.get("properties"):
120129
return "model"
121130
return "alias"
@@ -142,6 +151,15 @@ def resolve(self, schema: ctx.RawSchema, *, hint: str = "Inline") -> TypeInfo:
142151
if schema.get("x-algokit-signed-txn"):
143152
info = TypeInfo(annotation="SignedTransaction", model="SignedTransaction", is_signed_transaction=True)
144153
return self._maybe_optional(info, nullable=nullable)
154+
if schema.get("x-algokit-box-reference"):
155+
info = TypeInfo(annotation="BoxReference", model="BoxReference", is_box_reference=True)
156+
return self._maybe_optional(info, nullable=nullable)
157+
if schema.get("x-algokit-locals-reference"):
158+
info = TypeInfo(annotation="LocalsReference", model="LocalsReference", is_locals_reference=True)
159+
return self._maybe_optional(info, nullable=nullable)
160+
if schema.get("x-algokit-holding-reference"):
161+
info = TypeInfo(annotation="HoldingReference", model="HoldingReference", is_holding_reference=True)
162+
return self._maybe_optional(info, nullable=nullable)
145163
if schema_type == "array":
146164
info = self._resolve_array(schema, hint=hint)
147165
return self._maybe_optional(info, nullable=nullable)
@@ -183,6 +201,12 @@ def _type_from_entry(self, entry: SchemaEntry, *, hint: str) -> TypeInfo:
183201
return TypeInfo(annotation=entry.python_name, enum=entry.python_name)
184202
if entry.kind == "signed":
185203
return TypeInfo(annotation="SignedTransaction", model="SignedTransaction", is_signed_transaction=True)
204+
if entry.kind == "box_reference":
205+
return TypeInfo(annotation="BoxReference", model="BoxReference", is_box_reference=True)
206+
if entry.kind == "locals_reference":
207+
return TypeInfo(annotation="LocalsReference", model="LocalsReference", is_locals_reference=True)
208+
if entry.kind == "holding_reference":
209+
return TypeInfo(annotation="HoldingReference", model="HoldingReference", is_holding_reference=True)
186210
return self.resolve(entry.schema, hint=hint)
187211

188212
def _resolve_array(self, schema: ctx.RawSchema, *, hint: str) -> TypeInfo:
@@ -196,6 +220,9 @@ def _resolve_array(self, schema: ctx.RawSchema, *, hint: str) -> TypeInfo:
196220
list_inner_enum=inner.enum,
197221
list_inner_is_bytes=inner.is_bytes,
198222
is_signed_transaction=inner.is_signed_transaction,
223+
is_box_reference=inner.is_box_reference,
224+
is_locals_reference=inner.is_locals_reference,
225+
is_holding_reference=inner.is_holding_reference,
199226
needs_datetime=inner.needs_datetime,
200227
imports=set(inner.imports),
201228
)
@@ -212,6 +239,9 @@ def __init__(self, registry: SchemaRegistry, resolver: TypeResolver, sanitizer:
212239
self.resolver = resolver
213240
self.sanitizer = sanitizer
214241
self.uses_signed_transaction = False
242+
self.uses_box_reference = False
243+
self.uses_locals_reference = False
244+
self.uses_holding_reference = False
215245

216246
def _compute_default_value(self, type_info: TypeInfo, prop_schema: ctx.RawSchema) -> str | None:
217247
"""Compute default value for a required field based on its type.
@@ -293,6 +323,9 @@ def build(self) -> tuple[list[ctx.ModelDescriptor], list[ctx.EnumDescriptor], li
293323
models.append(self._build_model(entry))
294324
elif entry.kind == "enum":
295325
enums.append(self._build_enum(entry))
326+
elif entry.kind in ("signed", "box_reference", "locals_reference", "holding_reference"):
327+
# These are imported from algokit_transact, not generated
328+
pass
296329
elif entry.kind == "alias":
297330
alias_type = self.resolver.resolve(entry.schema).annotation
298331
alias_imports = self._collect_alias_imports(alias_type, entry)
@@ -328,6 +361,15 @@ def _build_model(self, entry: SchemaEntry) -> ctx.ModelDescriptor: # noqa: C901
328361
if type_info.is_signed_transaction:
329362
self.uses_signed_transaction = True
330363
imports.add("from algokit_transact.models.signed_transaction import SignedTransaction")
364+
if type_info.is_box_reference:
365+
self.uses_box_reference = True
366+
imports.add("from algokit_transact.models.app_call import BoxReference")
367+
if type_info.is_locals_reference:
368+
self.uses_locals_reference = True
369+
imports.add("from algokit_transact.models.app_call import LocalsReference")
370+
if type_info.is_holding_reference:
371+
self.uses_holding_reference = True
372+
imports.add("from algokit_transact.models.app_call import HoldingReference")
331373
annotation = type_info.annotation
332374
if prop_name not in required and "| None" not in annotation:
333375
annotation = f"{annotation} | None"
@@ -384,13 +426,22 @@ def _build_model(self, entry: SchemaEntry) -> ctx.ModelDescriptor: # noqa: C901
384426
if dep_module != entry.module_name:
385427
imports.add(f"from .{dep_module} import {dep_entry.python_name}")
386428
if type_info.list_inner_model:
387-
dep_entry = self.registry.entries_by_python_name.get(type_info.list_inner_model)
388-
if dep_entry:
389-
dep_module = _get_import_module(dep_entry.python_name, dep_entry.module_name)
390-
if dep_module != entry.module_name:
391-
imports.add(f"from .{dep_module} import {dep_entry.python_name}")
429+
# Handle special external types first
392430
if type_info.list_inner_model == "SignedTransaction":
393431
imports.add("from algokit_transact.models.signed_transaction import SignedTransaction")
432+
elif type_info.list_inner_model == "BoxReference" and type_info.is_box_reference:
433+
imports.add("from algokit_transact.models.app_call import BoxReference")
434+
elif type_info.list_inner_model == "LocalsReference" and type_info.is_locals_reference:
435+
imports.add("from algokit_transact.models.app_call import LocalsReference")
436+
elif type_info.list_inner_model == "HoldingReference" and type_info.is_holding_reference:
437+
imports.add("from algokit_transact.models.app_call import HoldingReference")
438+
else:
439+
# Only add local import if not a special external type
440+
dep_entry = self.registry.entries_by_python_name.get(type_info.list_inner_model)
441+
if dep_entry:
442+
dep_module = _get_import_module(dep_entry.python_name, dep_entry.module_name)
443+
if dep_module != entry.module_name:
444+
imports.add(f"from .{dep_module} import {dep_entry.python_name}")
394445
if type_info.enum:
395446
dep_entry = self.registry.entries_by_python_name.get(type_info.enum)
396447
if dep_entry:
@@ -483,7 +534,7 @@ def _forward_reference_tokens(self, entry: SchemaEntry, type_info: TypeInfo) ->
483534
def _requires_direct_forward_reference(self, entry: SchemaEntry, type_info: TypeInfo) -> bool:
484535
if not type_info.model:
485536
return False
486-
if type_info.model == "SignedTransaction":
537+
if type_info.model in ("SignedTransaction", "BoxReference", "LocalsReference", "HoldingReference"):
487538
return False
488539
if type_info.model == entry.python_name:
489540
return True
@@ -551,6 +602,12 @@ def _build_metadata(self, wire_name: str, type_info: TypeInfo, *, required: bool
551602
)
552603
if type_info.is_signed_transaction:
553604
return f'nested("{alias}", lambda: SignedTransaction)'
605+
if type_info.is_box_reference:
606+
return f'nested("{alias}", lambda: BoxReference)'
607+
if type_info.is_locals_reference:
608+
return f'nested("{alias}", lambda: LocalsReference)'
609+
if type_info.is_holding_reference:
610+
return f'nested("{alias}", lambda: HoldingReference)'
554611
return f'wire("{alias}")'
555612

556613
def _collect_alias_imports(self, annotation: str, entry: SchemaEntry) -> list[str]:
@@ -580,6 +637,15 @@ def _collect_alias_imports(self, annotation: str, entry: SchemaEntry) -> list[st
580637
if token == "SignedTransaction":
581638
imports.add("from algokit_transact.models.signed_transaction import SignedTransaction")
582639
continue
640+
if token == "BoxReference":
641+
imports.add("from algokit_transact.models.app_call import BoxReference")
642+
continue
643+
if token == "LocalsReference":
644+
imports.add("from algokit_transact.models.app_call import LocalsReference")
645+
continue
646+
if token == "HoldingReference":
647+
imports.add("from algokit_transact.models.app_call import HoldingReference")
648+
continue
583649
dep_entry = self.registry.entries_by_python_name.get(token)
584650
if dep_entry:
585651
imports.add(f"from .{dep_entry.module_name} import {dep_entry.python_name}")
@@ -941,6 +1007,9 @@ def build_client_descriptor(
9411007
default_base_url=base_url,
9421008
token_header=token_header,
9431009
uses_signed_transaction=uses_signed_txn,
1010+
uses_box_reference=model_builder.uses_box_reference,
1011+
uses_locals_reference=model_builder.uses_locals_reference,
1012+
uses_holding_reference=model_builder.uses_holding_reference,
9441013
uses_msgpack=operation_builder.uses_msgpack,
9451014
include_block_models=operation_builder.uses_block_models,
9461015
include_ledger_state_delta=operation_builder.uses_ledger_state_delta,

api/oas-generator/src/oas_generator/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ class ClientDescriptor:
153153
default_base_url: str
154154
token_header: str
155155
uses_signed_transaction: bool = False
156+
uses_box_reference: bool = False
157+
uses_locals_reference: bool = False
158+
uses_holding_reference: bool = False
156159
uses_msgpack: bool = False
157160
include_block_models: bool = False
158161
is_algod_client: bool = False

api/oas-generator/src/oas_generator/renderer/templates/models/__init__.py.j2

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11

22

33
{% if client.uses_signed_transaction %}from algokit_transact.models.signed_transaction import SignedTransaction
4+
{% endif %}{% if client.uses_box_reference %}from algokit_transact.models.app_call import BoxReference
5+
{% endif %}{% if client.uses_locals_reference %}from algokit_transact.models.app_call import LocalsReference
6+
{% endif %}{% if client.uses_holding_reference %}from algokit_transact.models.app_call import HoldingReference
47
{% endif %}{% for item in model_modules %}from .{{ item.module }} import {{ item.name }}
58
{% endfor %}{% for item in enum_modules %}from .{{ item.module }} import {{ item.name }}
69
{% endfor %}{% for item in alias_modules %}from .{{ item.module }} import {{ item.name }}
@@ -14,6 +17,9 @@
1417
{% endif %}
1518

1619
__all__ = [
17-
{% for name in model_exports %}"{{ name }}",
20+
{% if client.uses_box_reference %}"BoxReference",
21+
{% endif %}{% if client.uses_locals_reference %}"LocalsReference",
22+
{% endif %}{% if client.uses_holding_reference %}"HoldingReference",
23+
{% endif %}{% for name in model_exports %}"{{ name }}",
1824
{% endfor %}
1925
]

src/algokit_algod_client/models/__init__.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# AUTO-GENERATED: oas_generator
22

33

4+
from algokit_transact.models.app_call import BoxReference, HoldingReference, LocalsReference
45
from algokit_transact.models.signed_transaction import SignedTransaction
56

67
from ._account import Account
@@ -13,14 +14,12 @@
1314
from ._application import Application
1415
from ._application_initial_states import ApplicationInitialStates
1516
from ._application_kvstorage import ApplicationKvstorage
16-
from ._application_local_reference import ApplicationLocalReference
1717
from ._application_local_state import ApplicationLocalState
1818
from ._application_params import ApplicationParams
1919
from ._application_state_operation import ApplicationStateOperation
2020
from ._application_state_schema import ApplicationStateSchema
2121
from ._asset import Asset
2222
from ._asset_holding import AssetHolding
23-
from ._asset_holding_reference import AssetHoldingReference
2423
from ._asset_params import AssetParams
2524
from ._avm_key_value import AvmKeyValue
2625
from ._avm_value import AvmValue
@@ -43,7 +42,6 @@
4342
from ._block_txids_response import BlockTxidsResponse
4443
from ._box import Box
4544
from ._box_descriptor import BoxDescriptor
46-
from ._box_reference import BoxReference
4745
from ._boxes_response import BoxesResponse
4846
from ._build_version_contains_the_current_algod_build_version_information import (
4947
BuildVersionContainsTheCurrentAlgodBuildVersionInformation,
@@ -125,15 +123,13 @@
125123
"Application",
126124
"ApplicationInitialStates",
127125
"ApplicationKvstorage",
128-
"ApplicationLocalReference",
129126
"ApplicationLocalState",
130127
"ApplicationParams",
131128
"ApplicationStateOperation",
132129
"ApplicationStateSchema",
133130
"ApplyData",
134131
"Asset",
135132
"AssetHolding",
136-
"AssetHoldingReference",
137133
"AssetParams",
138134
"AvmKeyValue",
139135
"AvmValue",
@@ -163,6 +159,7 @@
163159
"GetBlockTimeStampOffsetResponse",
164160
"GetSyncRoundResponse",
165161
"GetTransactionGroupLedgerStateDeltasForRound",
162+
"HoldingReference",
166163
"LedgerAccountBaseData",
167164
"LedgerAccountData",
168165
"LedgerAccountDeltas",
@@ -188,6 +185,7 @@
188185
"LedgerTealValue",
189186
"LedgerVotingData",
190187
"LightBlockHeaderProof",
188+
"LocalsReference",
191189
"NodeStatusResponse",
192190
"ParticipationUpdates",
193191
"PendingTransactionResponse",

src/algokit_algod_client/models/_application_local_reference.py

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/algokit_algod_client/models/_application_state_schema.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ class ApplicationStateSchema:
1212
Specifies maximums on the number of each type that may be stored.
1313
"""
1414

15-
num_byte_slice: int = field(
15+
num_byte_slices: int = field(
1616
default=0,
1717
metadata=wire("num-byte-slice"),
1818
)
19-
num_uint: int = field(
19+
num_uints: int = field(
2020
default=0,
2121
metadata=wire("num-uint"),
2222
)

src/algokit_algod_client/models/_asset_holding_reference.py

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/algokit_algod_client/models/_box_reference.py

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/algokit_algod_client/models/_simulate_unnamed_resources_accessed.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
from dataclasses import dataclass, field
55

66
from algokit_common.serde import wire
7+
from algokit_transact.models.app_call import BoxReference, HoldingReference, LocalsReference
78

8-
from ._application_local_reference import ApplicationLocalReference
9-
from ._asset_holding_reference import AssetHoldingReference
10-
from ._box_reference import BoxReference
119
from ._serde_helpers import decode_model_sequence, encode_model_sequence
1210

1311

@@ -28,24 +26,24 @@ class SimulateUnnamedResourcesAccessed:
2826
default=None,
2927
metadata=wire("accounts"),
3028
)
31-
app_locals: list[ApplicationLocalReference] | None = field(
29+
app_locals: list[LocalsReference] | None = field(
3230
default=None,
3331
metadata=wire(
3432
"app-locals",
3533
encode=encode_model_sequence,
36-
decode=lambda raw: decode_model_sequence(lambda: ApplicationLocalReference, raw),
34+
decode=lambda raw: decode_model_sequence(lambda: LocalsReference, raw),
3735
),
3836
)
3937
apps: list[int] | None = field(
4038
default=None,
4139
metadata=wire("apps"),
4240
)
43-
asset_holdings: list[AssetHoldingReference] | None = field(
41+
asset_holdings: list[HoldingReference] | None = field(
4442
default=None,
4543
metadata=wire(
4644
"asset-holdings",
4745
encode=encode_model_sequence,
48-
decode=lambda raw: decode_model_sequence(lambda: AssetHoldingReference, raw),
46+
decode=lambda raw: decode_model_sequence(lambda: HoldingReference, raw),
4947
),
5048
)
5149
assets: list[int] | None = field(

0 commit comments

Comments
 (0)