Skip to content

Commit c1a4856

Browse files
refactor(v1): use classmethod for alternate constructors
Apply the same idiomatic Python refactor to the v1 SDK: convert @staticmethod factory methods (generate, load, from_*, parse, deserialize, natural, etc.) to @classmethod. Utility methods that are not constructors remain @staticmethod: - Serializer.sequence_serializer - PrivateKey.format_private_key / parse_hex_input - AptosCLIWrapper helpers - PackagePublisher payload/chunk helpers - AptosTokenClient.create_collection_payload / mint_token_payload - Metadata.get_aptos_header_val Co-authored-by: Greg Nazario <greg@gnazar.io>
1 parent 7f23fa5 commit c1a4856

10 files changed

Lines changed: 284 additions & 288 deletions

aptos_sdk/account.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,48 +31,48 @@ def __eq__(self, other: object) -> bool:
3131
self.account_address == other.account_address and self.private_key == other.private_key
3232
)
3333

34-
@staticmethod
35-
def generate() -> Account:
34+
@classmethod
35+
def generate(cls) -> Account:
3636
"""Generate a new Ed25519 account with a random private key.
3737
3838
:returns: A new Account with a freshly generated Ed25519 key pair.
3939
"""
4040
private_key = ed25519.PrivateKey.random()
4141
account_address = AccountAddress.from_key(private_key.public_key())
42-
return Account(account_address, private_key)
42+
return cls(account_address, private_key)
4343

44-
@staticmethod
45-
def generate_secp256k1_ecdsa() -> Account:
44+
@classmethod
45+
def generate_secp256k1_ecdsa(cls) -> Account:
4646
"""Generate a new Secp256k1 ECDSA account with a random private key.
4747
4848
:returns: A new Account with a freshly generated Secp256k1 key pair.
4949
"""
5050
private_key = secp256k1_ecdsa.PrivateKey.random()
5151
public_key = asymmetric_crypto_wrapper.PublicKey(private_key.public_key())
5252
account_address = AccountAddress.from_key(public_key)
53-
return Account(account_address, private_key)
53+
return cls(account_address, private_key)
5454

55-
@staticmethod
56-
def load_key(key: str) -> Account:
55+
@classmethod
56+
def load_key(cls, key: str) -> Account:
5757
"""Create an Account from an Ed25519 private key hex string.
5858
5959
:param key: Hex-encoded private key string.
6060
:returns: An Account derived from the given private key.
6161
"""
6262
private_key = ed25519.PrivateKey.from_str(key)
6363
account_address = AccountAddress.from_key(private_key.public_key())
64-
return Account(account_address, private_key)
64+
return cls(account_address, private_key)
6565

66-
@staticmethod
67-
def load(path: str) -> Account:
66+
@classmethod
67+
def load(cls, path: str) -> Account:
6868
"""Load an Account from a JSON file containing ``account_address`` and ``private_key``.
6969
7070
:param path: Path to the JSON file.
7171
:returns: The deserialized Account.
7272
"""
7373
with open(path) as file:
7474
data = json.load(file)
75-
return Account(
75+
return cls(
7676
AccountAddress.from_str_relaxed(data["account_address"]),
7777
ed25519.PrivateKey.from_str(data["private_key"]),
7878
)

aptos_sdk/account_address.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ def is_special(self):
8383
"""
8484
return all(b == 0 for b in self.address[:-1]) and self.address[-1] < 0b10000
8585

86-
@staticmethod
87-
def from_str(address: str) -> AccountAddress:
86+
@classmethod
87+
def from_str(cls, address: str) -> AccountAddress:
8888
"""
8989
NOTE: This function has strict parsing behavior. For relaxed behavior, please use
9090
`from_string_relaxed` function.
@@ -117,7 +117,7 @@ def from_str(address: str) -> AccountAddress:
117117
if not address.startswith("0x"):
118118
raise RuntimeError("Hex string must start with a leading 0x.")
119119

120-
out = AccountAddress.from_str_relaxed(address)
120+
out = cls.from_str_relaxed(address)
121121

122122
# Check if the address is in LONG form. If it is not, this is only allowed for
123123
# special addresses, in which case we check it is in proper SHORT form.
@@ -144,8 +144,8 @@ def from_str(address: str) -> AccountAddress:
144144

145145
return out
146146

147-
@staticmethod
148-
def from_str_relaxed(address: str) -> AccountAddress:
147+
@classmethod
148+
def from_str_relaxed(cls, address: str) -> AccountAddress:
149149
"""
150150
NOTE: This function has relaxed parsing behavior. For strict behavior, please use
151151
the `from_string` function. Where possible, use `from_string` rather than this
@@ -194,10 +194,10 @@ def from_str_relaxed(address: str) -> AccountAddress:
194194
pad = "0" * (AccountAddress.LENGTH * 2 - len(addr))
195195
addr = pad + addr
196196

197-
return AccountAddress(bytes.fromhex(addr))
197+
return cls(bytes.fromhex(addr))
198198

199-
@staticmethod
200-
def from_key(key: asymmetric_crypto.PublicKey) -> AccountAddress:
199+
@classmethod
200+
def from_key(cls, key: asymmetric_crypto.PublicKey) -> AccountAddress:
201201
hasher = hashlib.sha3_256()
202202
hasher.update(key.to_crypto_bytes())
203203

@@ -212,49 +212,49 @@ def from_key(key: asymmetric_crypto.PublicKey) -> AccountAddress:
212212
else:
213213
raise InvalidKeyError("Unsupported asymmetric_crypto.PublicKey key type.")
214214

215-
return AccountAddress(hasher.digest())
215+
return cls(hasher.digest())
216216

217-
@staticmethod
218-
def for_resource_account(creator: AccountAddress, seed: bytes) -> AccountAddress:
217+
@classmethod
218+
def for_resource_account(cls, creator: AccountAddress, seed: bytes) -> AccountAddress:
219219
hasher = hashlib.sha3_256()
220220
hasher.update(creator.address)
221221
hasher.update(seed)
222222
hasher.update(AuthKeyScheme.DeriveResourceAccountAddress)
223-
return AccountAddress(hasher.digest())
223+
return cls(hasher.digest())
224224

225-
@staticmethod
226-
def for_guid_object(creator: AccountAddress, creation_num: int) -> AccountAddress:
225+
@classmethod
226+
def for_guid_object(cls, creator: AccountAddress, creation_num: int) -> AccountAddress:
227227
hasher = hashlib.sha3_256()
228228
serializer = Serializer()
229229
serializer.u64(creation_num)
230230
hasher.update(serializer.output())
231231
hasher.update(creator.address)
232232
hasher.update(AuthKeyScheme.DeriveObjectAddressFromGuid)
233-
return AccountAddress(hasher.digest())
233+
return cls(hasher.digest())
234234

235-
@staticmethod
236-
def for_named_object(creator: AccountAddress, seed: bytes) -> AccountAddress:
235+
@classmethod
236+
def for_named_object(cls, creator: AccountAddress, seed: bytes) -> AccountAddress:
237237
hasher = hashlib.sha3_256()
238238
hasher.update(creator.address)
239239
hasher.update(seed)
240240
hasher.update(AuthKeyScheme.DeriveObjectAddressFromSeed)
241-
return AccountAddress(hasher.digest())
241+
return cls(hasher.digest())
242242

243-
@staticmethod
243+
@classmethod
244244
def for_named_token(
245-
creator: AccountAddress, collection_name: str, token_name: str
245+
cls, creator: AccountAddress, collection_name: str, token_name: str
246246
) -> AccountAddress:
247247
collection_bytes = collection_name.encode()
248248
token_bytes = token_name.encode()
249-
return AccountAddress.for_named_object(creator, collection_bytes + b"::" + token_bytes)
249+
return cls.for_named_object(creator, collection_bytes + b"::" + token_bytes)
250250

251-
@staticmethod
252-
def for_named_collection(creator: AccountAddress, collection_name: str) -> AccountAddress:
253-
return AccountAddress.for_named_object(creator, collection_name.encode())
251+
@classmethod
252+
def for_named_collection(cls, creator: AccountAddress, collection_name: str) -> AccountAddress:
253+
return cls.for_named_object(creator, collection_name.encode())
254254

255-
@staticmethod
256-
def deserialize(deserializer: Deserializer) -> AccountAddress:
257-
return AccountAddress(deserializer.fixed_bytes(AccountAddress.LENGTH))
255+
@classmethod
256+
def deserialize(cls, deserializer: Deserializer) -> AccountAddress:
257+
return cls(deserializer.fixed_bytes(AccountAddress.LENGTH))
258258

259259
def serialize(self, serializer: Serializer):
260260
serializer.fixed_bytes(self.address)

aptos_sdk/aptos_token_client.py

Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ def __init__(self, allow_ungated_transfer, owner):
2323
self.allow_ungated_transfer = allow_ungated_transfer
2424
self.owner = owner
2525

26-
@staticmethod
27-
def parse(resource: dict[str, Any]) -> Object:
28-
return Object(
26+
@classmethod
27+
def parse(cls, resource: dict[str, Any]) -> Object:
28+
return cls(
2929
resource["allow_ungated_transfer"],
3030
AccountAddress.from_str_relaxed(resource["owner"]),
3131
)
@@ -51,9 +51,9 @@ def __init__(self, creator, description, name, uri):
5151
def __str__(self) -> str:
5252
return f"AccountAddress[creator: {self.creator}, description: {self.description}, name: {self.name}, ur: {self.uri}]"
5353

54-
@staticmethod
55-
def parse(resource: dict[str, Any]) -> Collection:
56-
return Collection(
54+
@classmethod
55+
def parse(cls, resource: dict[str, Any]) -> Collection:
56+
return cls(
5757
AccountAddress.from_str_relaxed(resource["creator"]),
5858
resource["description"],
5959
resource["name"],
@@ -76,9 +76,9 @@ def __init__(self, numerator, denominator, payee_address):
7676
def __str__(self) -> str:
7777
return f"Royalty[numerator: {self.numerator}, denominator: {self.denominator}, payee_address: {self.payee_address}]"
7878

79-
@staticmethod
80-
def parse(resource: dict[str, Any]) -> Royalty:
81-
return Royalty(
79+
@classmethod
80+
def parse(cls, resource: dict[str, Any]) -> Royalty:
81+
return cls(
8282
resource["numerator"],
8383
resource["denominator"],
8484
AccountAddress.from_str_relaxed(resource["payee_address"]),
@@ -111,9 +111,9 @@ def __init__(
111111
def __str__(self) -> str:
112112
return f"Token[collection: {self.collection}, index: {self.index}, description: {self.description}, name: {self.name}, uri: {self.uri}]"
113113

114-
@staticmethod
115-
def parse(resource: dict[str, Any]):
116-
return Token(
114+
@classmethod
115+
def parse(cls, resource: dict[str, Any]):
116+
return cls(
117117
AccountAddress.from_str_relaxed(resource["collection"]["inner"]),
118118
int(resource["index"]),
119119
resource["description"],
@@ -190,67 +190,67 @@ def to_transaction_arguments(self) -> List[TransactionArgument]:
190190
TransactionArgument(self.serialize_value(), Serializer.to_bytes),
191191
]
192192

193-
@staticmethod
194-
def parse(name: str, property_type: int, value: bytes) -> Property:
193+
@classmethod
194+
def parse(cls, name: str, property_type: int, value: bytes) -> Property:
195195
deserializer = Deserializer(value)
196196

197197
if property_type == Property.BOOL:
198-
return Property(name, "bool", deserializer.bool())
198+
return cls(name, "bool", deserializer.bool())
199199
elif property_type == Property.U8:
200-
return Property(name, "u8", deserializer.u8())
200+
return cls(name, "u8", deserializer.u8())
201201
elif property_type == Property.U16:
202-
return Property(name, "u16", deserializer.u16())
202+
return cls(name, "u16", deserializer.u16())
203203
elif property_type == Property.U32:
204-
return Property(name, "u32", deserializer.u32())
204+
return cls(name, "u32", deserializer.u32())
205205
elif property_type == Property.U64:
206-
return Property(name, "u64", deserializer.u64())
206+
return cls(name, "u64", deserializer.u64())
207207
elif property_type == Property.U128:
208-
return Property(name, "u128", deserializer.u128())
208+
return cls(name, "u128", deserializer.u128())
209209
elif property_type == Property.U256:
210-
return Property(name, "u256", deserializer.u256())
210+
return cls(name, "u256", deserializer.u256())
211211
elif property_type == Property.ADDRESS:
212-
return Property(name, "address", AccountAddress.deserialize(deserializer))
212+
return cls(name, "address", AccountAddress.deserialize(deserializer))
213213
elif property_type == Property.STRING:
214-
return Property(name, "0x1::string::String", deserializer.str())
214+
return cls(name, "0x1::string::String", deserializer.str())
215215
elif property_type == Property.BYTE_VECTOR:
216-
return Property(name, "vector<u8>", deserializer.to_bytes())
216+
return cls(name, "vector<u8>", deserializer.to_bytes())
217217
raise InvalidPropertyType(property_type)
218218

219-
@staticmethod
220-
def bool(name: str, value: bool) -> Property:
221-
return Property(name, "bool", value)
219+
@classmethod
220+
def bool(cls, name: str, value: bool) -> Property:
221+
return cls(name, "bool", value)
222222

223-
@staticmethod
224-
def u8(name: str, value: int) -> Property:
225-
return Property(name, "u8", value)
223+
@classmethod
224+
def u8(cls, name: str, value: int) -> Property:
225+
return cls(name, "u8", value)
226226

227-
@staticmethod
228-
def u16(name: str, value: int) -> Property:
229-
return Property(name, "u16", value)
227+
@classmethod
228+
def u16(cls, name: str, value: int) -> Property:
229+
return cls(name, "u16", value)
230230

231-
@staticmethod
232-
def u32(name: str, value: int) -> Property:
233-
return Property(name, "u32", value)
231+
@classmethod
232+
def u32(cls, name: str, value: int) -> Property:
233+
return cls(name, "u32", value)
234234

235-
@staticmethod
236-
def u64(name: str, value: int) -> Property:
237-
return Property(name, "u64", value)
235+
@classmethod
236+
def u64(cls, name: str, value: int) -> Property:
237+
return cls(name, "u64", value)
238238

239-
@staticmethod
240-
def u128(name: str, value: int) -> Property:
241-
return Property(name, "u128", value)
239+
@classmethod
240+
def u128(cls, name: str, value: int) -> Property:
241+
return cls(name, "u128", value)
242242

243-
@staticmethod
244-
def u256(name: str, value: int) -> Property:
245-
return Property(name, "u256", value)
243+
@classmethod
244+
def u256(cls, name: str, value: int) -> Property:
245+
return cls(name, "u256", value)
246246

247-
@staticmethod
248-
def string(name: str, value: str) -> Property:
249-
return Property(name, "0x1::string::String", value)
247+
@classmethod
248+
def string(cls, name: str, value: str) -> Property:
249+
return cls(name, "0x1::string::String", value)
250250

251-
@staticmethod
252-
def bytes(name: str, value: bytes) -> Property:
253-
return Property(name, "vector<u8>", value)
251+
@classmethod
252+
def bytes(cls, name: str, value: bytes) -> Property:
253+
return cls(name, "vector<u8>", value)
254254

255255

256256
class PropertyMap:
@@ -282,8 +282,8 @@ def to_tuple(self) -> Tuple[List[str], List[str], List[bytes]]:
282282

283283
return (names, types, values)
284284

285-
@staticmethod
286-
def parse(resource: dict[str, Any]) -> PropertyMap:
285+
@classmethod
286+
def parse(cls, resource: dict[str, Any]) -> PropertyMap:
287287
props = resource["inner"]["data"]
288288
properties = []
289289
for prop in props:
@@ -295,7 +295,7 @@ def parse(resource: dict[str, Any]) -> PropertyMap:
295295
)
296296
)
297297

298-
return PropertyMap(properties)
298+
return cls(properties)
299299

300300

301301
class ReadObject:

0 commit comments

Comments
 (0)