Metadata-Version: 2.4
Name: anpyra
Version: 0.1.5
Summary: Compile a typed Python subset directly to Android DEX and signed APKs
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/babar-xagi/Anpyra
Project-URL: Documentation, https://github.com/babar-xagi/Anpyra/tree/main/docs
Project-URL: Repository, https://github.com/babar-xagi/Anpyra
Project-URL: Issues, https://github.com/babar-xagi/Anpyra/issues
Project-URL: Changelog, https://github.com/babar-xagi/Anpyra/blob/main/CHANGELOG.md
Keywords: android,python,compiler,dex,apk,native
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Compilers
Classifier: Topic :: Software Development :: Build Tools
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cryptography>=46.0.0
Requires-Dist: Pillow>=11.3.0
Provides-Extra: dev
Requires-Dist: ruff; extra == "dev"
Dynamic: license-file

# 🐍 Anpyra · Python to Native Android

Write small Android apps in a typed Python subset, compile them directly to DEX, and build signed APKs. Anpyra is a Python-written compiler and build framework based on the PyAndroid experiments 001–008.

**Status: v0.1.5 alpha. Android is the only implemented target.** This release adds named Python button callbacks, typed mutable Activity state, runtime input and explicit saved-instance save/restore. Native layouts, ChatSession and Screen/TextView/Button design remain available. API 33 acceptance includes 11 event/state cases and 15 mixed-controller cases alongside earlier component checks. Other Android versions, physical rotation/process restoration and independent ART verification still need coverage.

## 🐍 Python-based builds

Build with Python 3.11+ and Python dependencies. No Java/JDK, Kotlin, Android SDK build kit, Android NDK, Android Studio, Gradle, D8, R8, AAPT2 or apksigner is required. `cryptography` and Pillow are installed automatically for signing and Screen image/color handling. Optional adb provides device installation.

## ⚡ Install the published package

Install from PyPI using uv (recommended):

```shell
uv venv --python 3.12
uv pip install "anpyra==0.1.5"
```

Or use pip inside a virtual environment:

```shell
python -m pip install "anpyra==0.1.5"
```

Activate your environment, then:

```shell
anpyra doctor
anpyra init myapp --package dev.example.myapp --label "My App"
anpyra check myapp
anpyra build myapp
anpyra verify myapp/build/dev.example.myapp.apk
```

For checkout installation and host-specific commands, see the [installation guide](https://github.com/babar-xagi/Anpyra/blob/main/docs/user_guide/installation.md).

## 🔄 Upgrade from an earlier release

Use the same environment where you installed Anpyra. With that environment activated, choose uv (recommended) or pip:

```shell
uv pip install --upgrade "anpyra==0.1.5"
# Or:
python -m pip install --upgrade "anpyra==0.1.5"
python -m anpyra --version
```

The version should print `Anpyra 0.1.5`. To upgrade to the latest compatible release, use `--upgrade anpyra` without the version pin. Keep your app's `.anpyra/` signing identity and rebuild its APK after upgrading. See the [upgrade guide](https://github.com/babar-xagi/Anpyra/blob/main/docs/user_guide/installation.md) for explicit environment paths.

## 🧩 Application example

```python
from anpyra import Activity
from anpyra.components import Font, TextView


class MainActivity(Activity):
    def on_create(self, state):
        title = TextView(self, text="Hello from Anpyra!")
        title.style.color = "#663399"
        title.style.size = 28
        title.style.font = Font(family="sans-serif", bold=True)
        title.style.padding = (16, 24)
        title.style.width = "match_parent"
        title.style.alignment = "center"
        self.set_content_view(title)
```

Anpyra parses application source on the host. Android runs the generated bytecode. The authoring classes provide editor support; they do not preview a UI on the host.

## 🟦 Native Button example

```python
from anpyra import Activity
from anpyra.components import Button, Border


class MainActivity(Activity):
    def on_create(self, state):
        button = Button(self, text="Continue")
        button.style.bg.color = "#2563eb"
        button.style.color = "white"
        button.style.all_caps = False
        button.style.corner_radius = 16
        button.style.border = Border("#93c5fd", width=2)
        button.style.width = 260
        button.style.height = 64
        button.style.placement = "center"
        button.style.pressed.bg.color = "#1e40af"
        button.style.ripple_color = "#50ffffff"
        self.set_content_view(button)
```

This example demonstrates native design and press feedback. Bind named Activity click handlers using the [events/state API](https://github.com/babar-xagi/Anpyra/blob/main/docs/user_guide/events.md).

## 💬 Standalone chatbot

Use native layouts, TextInput, TextView and Button with ChatSession to call OpenAI directly from the phone. Enter a temporary key at runtime; it is not compiled into the APK. Successful turns retain all response output items, New chat resets history, and request controls recover after errors. No Python server or embedded OpenAI Python SDK is needed. See the [chatbot guide](https://github.com/babar-xagi/Anpyra/blob/main/docs/user_guide/chatbot.md) and [full example](https://github.com/babar-xagi/Anpyra/tree/main/examples/chatbot).

Chat checks use controlled responses. A live AI answer was not verified because the test key returned exhausted quota. Named generic callbacks can coexist on separate buttons; streaming, cancellation and durable chat history remain unsupported.

## 🖱️ Named callbacks and typed state

```python
from anpyra import Activity, Button, Column, State, TextView

class MainActivity(Activity):
    def on_create(self, state):
        self.count: int = State(0, persist=True)
        page = Column(self)
        label = TextView(self, text="0")
        self.label = label
        button = Button(self, text="Add one")
        button.on_click(self.increment)
        page.add(label)
        page.add(button)
        self.set_content_view(page)
        self.refresh()

    def increment(self):
        self.count += 1
        self.refresh()

    def refresh(self):
        self.label.set_text(str(self.count))
```

State persistence is opt-in and uses Android's saved-instance Bundle. Widget references are recreated; memory-only scalar fields start from defaults. Handler integers use signed-32-bit wraparound. See [usage and limits](https://github.com/babar-xagi/Anpyra/blob/main/docs/user_guide/events.md) and [Counter Lab](https://github.com/babar-xagi/Anpyra/tree/main/examples/counter).

## 📦 Supported features and limits

- One Activity and TextView with Font/Shadow/TextStyle declarations, constructor text, typography, dp dimensions/padding, sp size and native selection.
- Native Button design with shared typography, state colors, rounded shapes, stroke, ripple, layout/margins and signed raster icons.
- Column/Row weighted layouts, single-child ScrollView and TextInput with placeholder/password configuration.
- Scoped ChatSession listener, worker/delivery classes, HTTPS/JSON requests, response rendering and successful history.
- Named click handlers, stable int/str/bool fields and locals, runtime text/enabled operations and opted-in saved-instance state.
- Validated standalone local TTF/OTF fonts preserved in signed digest-named APK assets.
- Screen colors, local raster images with seven fit modes, linear/radial/sweep gradients and transparency.
- Initialized `str`, `int` and `bool` locals, simple integer arithmetic and comparisons.
- Nested conditions and typed integer helper functions.
- DEX, binary manifest, signed APK and JSON report generation.
- Retained project debug identity and local APK/DEX integrity checks.

This is a restricted compiler, not general Python on Android. Screen accepts one widget or layout root; Column/Row arrange multiple children. Lambdas, captured lifecycle locals, async handlers, arbitrary imports, collections, multi-module apps and release/store signing remain unsupported. Interactive apps permit 48 lifecycle symbols with at most 14 scalar int/bool locals, and eight scalar locals per handler; older apps retain their 14-symbol budget. See [events/state](https://github.com/babar-xagi/Anpyra/blob/main/docs/user_guide/events.md), [Screen](https://github.com/babar-xagi/Anpyra/blob/main/docs/user_guide/screen.md), [TextView](https://github.com/babar-xagi/Anpyra/blob/main/docs/user_guide/textview.md), [Button](https://github.com/babar-xagi/Anpyra/blob/main/docs/user_guide/button.md) and [language limits](https://github.com/babar-xagi/Anpyra/blob/main/docs/user_guide/language.md).

## 📚 Documentation and contribution

[User guide](https://github.com/babar-xagi/Anpyra/tree/main/docs/user_guide) · [Developer guide](https://github.com/babar-xagi/Anpyra/tree/main/docs/developer_guide) · [Roadmap](https://github.com/babar-xagi/Anpyra/blob/main/docs/roadmap.md) · [Issues](https://github.com/babar-xagi/Anpyra/issues) · [Contributing](https://github.com/babar-xagi/Anpyra/blob/main/CONTRIBUTING.md)

Anpyra is licensed under Apache-2.0.
