ApkPy 1.14.1¶
Released 2026-10-25. python -m pip install --upgrade apkpy==1.14.1.
Classes reach the phone. A class in writehere.py or in a helper module
is translated to Java, and an object behaves as it does in CPython.
@dataclass and errors of your own come with it.
from dataclasses import dataclass, field
class SoldOut(Exception):
pass
@dataclass
class Cart:
owner: str
items: list = field(default_factory=list)
def add(self, name, stock):
if stock == 0:
raise SoldOut(f"{name} is sold out")
self.items.append(name)
def buy():
cart = Cart("ana")
try:
cart.add("tea", 3)
cart.add("cake", 0)
except SoldOut as e:
out.set_value(f"{e}: {cart}")
On the phone the label reads cake is sold out: Cart(owner='ana', items=['tea']),
the same as in CPython.
Classes¶
__init__, methods, one parent class andsuper(), class attributes (Shape.count += 1),@staticmethod,@property, and__str__,__repr__and__eq__.- Every name that holds an object sees the same changes, so
tasks[0].done = Trueis seen through the list and through any other name for that task.isasks whether two names hold the same object,isinstance()andtype(x).__name__follow the family tree, and the method that runs is the one of the object's own class. Reading a field that was never set raisesAttributeError. - A field that is always given the same kind is read as that kind, so
self.price * self.qtyis arithmetic andself.items.append(x)changes the object's own list. - A method can be handed over as a value,
command=cart.clear. An object made at the top of the file is made once, when the app starts, and every screen sees the same one. - A helper module can hold classes:
import shop, thenshop.Product("tea", 2.0).
Dataclasses¶
@dataclass gives a class the __init__, __repr__ and __eq__ that
CPython writes from its fields, unless the class writes its own. The fields
take field(default=...), field(default_factory=list), init=, repr=
and compare=; a dataclass can extend another, and ClassVar and
__post_init__ work as in CPython.
Errors of your own¶
A class that extends an error is raised and caught like Python's own:
except ValueError catches class TooLong(ValueError): pass,
except AppError catches the errors that extend it, and str(e) is the
message. An __init__ that hands the message on with
super().__init__(message) can give it a default, used by raise NotFound().
A few forms stop the build at their line, each with one that compiles:
frozen=True and order=True on a dataclass, @classmethod, and fields or
methods on an error class. The whole list is on
Compatibility and limits.
Checked on a phone¶
Two new examples were built and run on a phone with Android 16:
examples/44_classes.py, a month's budget, and
examples/45_dataclasses_and_errors.py, a pantry list. At every step each
showed the labels that the same app shows in CPython, errors included. The
tests also run the generated Java of whole apps on the JVM and compare it
with CPython, line by line.
Fixed¶
- A module-level list that a function gives a new value with
global(ITEMS = [...]inside a function) was walked byforand searched byinas the list written at the top of the file, before the function ran.ITEMS[0]already read the new one. Present in 1.14.0. str()of a comparison or of a flag, put in a list ([str(a == b), "x"]), showed astrue/falsewhen the list was shown, where CPython showsTrue/False.- The AGENTS.md that
apkpy initwrites listed as refused much of the Python that 1.14.0 translates. It lists what is translated now, classes included.
Upgrade¶
python -m pip install --upgrade apkpy==1.14.1, and build again. Nothing in
an app has to change. Code with classes that stopped the build in 1.14.0 may
now build.
What stays different¶
An object shows its address, <__main__.Task object at 0x...>, and the
address differs from CPython's, as it does between two runs of CPython. A
list written as a default value, def __init__(self, tags=[]), is a new
list for each call on the phone, where CPython shares one list between the
calls; field(default_factory=list) gives every object its own in both.