| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -43,3 +43,57 @@ jobs: | |||
| 43 | 43 | ||
| 44 | 44 | - name: Run tests | |
| 45 | 45 | run: uv run pytest -q | |
| 46 | + | ||
| 47 | + # The Swift half of the rendering core: decoders, component managers, | ||
| 48 | + # gestures, and module promises run under XCTest on a simulator. | ||
| 49 | + native-ios: | ||
| 50 | + runs-on: macos-14 | ||
| 51 | + steps: | ||
| 52 | + - name: Checkout | ||
| 53 | + uses: actions/checkout@v4 | ||
| 54 | + | ||
| 55 | + # Runner images ship different simulator sets, and xcodebuild | ||
| 56 | + # silently falls back to "My Mac" (where UIKit doesn't exist) when | ||
| 57 | + # a named destination is missing, so resolve an available iPhone | ||
| 58 | + # simulator by UDID instead of hardcoding a model name. | ||
| 59 | + - name: Run PythonNativeKit tests | ||
| 60 | + working-directory: src/pythonnative/templates/ios_template/PythonNativeKit | ||
| 61 | + run: | | ||
| 62 | + set -o pipefail | ||
| 63 | + UDID="$(xcrun simctl list devices available -j | python3 -c ' | ||
| 64 | + import json, sys | ||
| 65 | + data = json.load(sys.stdin)["devices"] | ||
| 66 | + phones = [ | ||
| 67 | + d for runtime, devices in sorted(data.items()) if "iOS" in runtime | ||
| 68 | + for d in devices if d.get("isAvailable") and d["name"].startswith("iPhone") | ||
| 69 | + ] | ||
| 70 | + if not phones: | ||
| 71 | + sys.exit("no available iPhone simulator on this runner") | ||
| 72 | + print(phones[-1]["udid"]) | ||
| 73 | + ')" | ||
| 74 | + echo "Using simulator $UDID" | ||
| 75 | + xcodebuild test \ | ||
| 76 | + -scheme PythonNativeKit \ | ||
| 77 | + -destination "platform=iOS Simulator,id=$UDID" \ | ||
| 78 | + -derivedDataPath "$RUNNER_TEMP/pnkit" \ | ||
| 79 | + -quiet | ||
| 80 | + | ||
| 81 | + # The Kotlin half has no Chaquopy dependency, so plain JUnit covers it. | ||
| 82 | + native-android: | ||
| 83 | + runs-on: ubuntu-latest | ||
| 84 | + steps: | ||
| 85 | + - name: Checkout | ||
| 86 | + uses: actions/checkout@v4 | ||
| 87 | + | ||
| 88 | + - name: Set up Java 17 | ||
| 89 | + uses: actions/setup-java@v4 | ||
| 90 | + with: | ||
| 91 | + distribution: 'temurin' | ||
| 92 | + java-version: '17' | ||
| 93 | + | ||
| 94 | + - name: Set up Gradle | ||
| 95 | + uses: gradle/actions/setup-gradle@v4 | ||
| 96 | + | ||
| 97 | + - name: Run pythonnative module tests | ||
| 98 | + working-directory: src/pythonnative/templates/android_template | ||
| 99 | + run: ./gradlew :pythonnative:testDebugUnitTest --no-daemon | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -127,28 +127,36 @@ jobs: | |||
| 127 | 127 | runs-on: macos-15 | |
| 128 | 128 | # Budget for the worst case: ~8 min build/boot plus two full suite | |
| 129 | 129 | # attempts (run-e2e.sh retries the whole suite once after a driver | |
| 130 | - # flake) at up to ~20 min each on a slow runner. 40 was enough for | ||
| 131 | - # a clean pass but cut the retry off mid-suite. | ||
| 130 | + # flake). The test step gets its own, shorter timeout so a hung | ||
| 131 | + # attempt still leaves time for the debug-output upload below; | ||
| 132 | + # a job-level timeout kills the runner before that step can run. | ||
| 132 | 133 | timeout-minutes: 55 | |
| 133 | 134 | # iOS simulators are stable for the full suite (unlike the Android | |
| 134 | 135 | # emulator; see the e2e-android note), so this split is purely a | |
| 135 | 136 | # speed optimization: the iOS Maestro run is ~22 minutes and is the | |
| 136 | - # critical path for the whole E2E workflow. Sharding it across three | ||
| 137 | + # critical path for the whole E2E workflow. Sharding it across | ||
| 137 | 138 | # simulators (same balanced groups as Android) runs them in parallel | |
| 138 | 139 | # and roughly halves wall-clock time. macOS minutes are free on this | |
| 139 | 140 | # public repo, so the extra per-shard build/boot overhead is fine. | |
| 141 | + # Shards are sized so a single attempt is ~10-12 minutes of driving: | ||
| 142 | + # ``components`` alone was ~21 minutes per attempt on a hosted | ||
| 143 | + # runner, so one retry (build + two attempts) overran the job budget. | ||
| 140 | 144 | # ``fail-fast: false`` so one shard's failure still lets the others | |
| 141 | 145 | # report. | |
| 142 | 146 | strategy: | |
| 143 | 147 | fail-fast: false | |
| 144 | 148 | matrix: | |
| 145 | 149 | include: | |
| 146 | - - name: components | ||
| 147 | - suites: components | ||
| 148 | - - name: hooks-nav-gestures | ||
| 149 | - suites: hooks navigation gestures | ||
| 150 | - - name: layout-styling-anim-misc | ||
| 151 | - suites: layout styling animations misc | ||
| 150 | + - name: components-a | ||
| 151 | + suites: components-a | ||
| 152 | + - name: components-b | ||
| 153 | + suites: components-b | ||
| 154 | + - name: hooks | ||
| 155 | + suites: hooks | ||
| 156 | + - name: nav-gestures-layout-styling | ||
| 157 | + suites: navigation gestures layout styling | ||
| 158 | + - name: anim-misc | ||
| 159 | + suites: animations misc | ||
| 152 | 160 | ||
| 153 | 161 | name: e2e-ios (${{ matrix.name }}) | |
| 154 | 162 | ||
@@ -175,13 +183,15 @@ jobs: | |||
| 175 | 183 | echo "$HOME/.maestro/bin" >> $GITHUB_PATH | |
| 176 | 184 | ||
| 177 | 185 | - name: Build and run E2E tests | |
| 186 | + timeout-minutes: 48 | ||
| 178 | 187 | run: uv run ./scripts/run-e2e.sh ios ${{ matrix.suites }} | |
| 179 | 188 | env: | |
| 180 | 189 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| 181 | 190 | ||
| 182 | 191 | # Maestro writes per-flow debug output (command log, view-hierarchy | |
| 183 | 192 | # dumps, failure screenshots) under ~/.maestro/tests. Surface it when | |
| 184 | - # a shard fails so CI-only failures are diagnosable without guesswork. | ||
| 193 | + # a shard fails (or hits the step timeout above) so CI-only failures | ||
| 194 | + # are diagnosable without guesswork. | ||
| 185 | 195 | - name: Upload Maestro debug output | |
| 186 | 196 | if: failure() | |
| 187 | 197 | uses: actions/upload-artifact@v4 | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -63,8 +63,12 @@ Unsolicited pull requests for issues that are already assigned or already have a | |||
| 63 | 63 | ||
| 64 | 64 | - `src/pythonnative/`: installable library and CLI | |
| 65 | 65 | - `pythonnative/`: core cross‑platform UI components and utilities | |
| 66 | + - `bridge/`: JSON codec and per-platform transports into the native rendering core | ||
| 66 | 67 | - `cli/`: `pn` command | |
| 68 | + - `project/`: config loading, template configuration, native plugin staging, and the builder behind `pn` | ||
| 67 | 69 | - `templates/`: Android/iOS project templates (bundled with the package) | |
| 70 | + - `ios_template/PythonNativeKit/`: Swift package with the iOS rendering core (component managers, gestures, animations, native modules) and its XCTest target | ||
| 71 | + - `android_template/pythonnative/`: Gradle library module with the Android rendering core and its JUnit target | ||
| 68 | 72 | - `tests/`: unit tests for the library, plus the Maestro E2E suite | |
| 69 | 73 | - `e2e/`: the comprehensive E2E suite (see [E2E tests](#e2e-tests-maestro) below and `tests/e2e/AGENTS.md`) | |
| 70 | 74 | - `examples/`: runnable example apps | |
@@ -77,7 +81,8 @@ Unsolicited pull requests for issues that are already assigned or already have a | |||
| 77 | 81 | ||
| 78 | 82 | - Style: Black; lint: Ruff; typing where useful. Keep APIs stable. | |
| 79 | 83 | - Prefer explicit, descriptive names; keep platform abstractions clean. | |
| 80 | - - Add/extend tests under `tests/` for new behavior. | ||
| 84 | + - Python never imports platform code. Everything that touches `UIView` or `android.view.View` lives in Swift (`PythonNativeKit`) or Kotlin (the `pythonnative` Gradle module) and is reached through `pythonnative.bridge`; see `docs/concepts/bridge.md` for the protocol. Bump `PROTOCOL_VERSION` on both sides when the wire format changes. | ||
| 85 | + - Add/extend tests under `tests/` for new behavior. Native changes get XCTest / JUnit coverage next to the code they touch. | ||
| 81 | 86 | - Don't commit generated artifacts or large binaries; templates live under `src/pythonnative/templates/`. | |
| 82 | 87 | - Docstrings: Google style throughout. Ruff is configured with the Google | |
| 83 | 88 | convention (`pydocstyle.convention = "google"`) and enforces the `D` rule | |
@@ -94,6 +99,10 @@ uv run pytest -q # run tests | |||
| 94 | 99 | uv run ruff check . # lint | |
| 95 | 100 | uv run black src examples tests # format | |
| 96 | 101 | uv run --group docs mkdocs serve # preview the docs site locally | |
| 102 | + | ||
| 103 | + # native rendering core (macOS with Xcode for the Swift package; JDK 17 for Gradle) | ||
| 104 | + (cd src/pythonnative/templates/ios_template/PythonNativeKit && xcodebuild test -scheme PythonNativeKit -destination 'platform=iOS Simulator,name=iPhone 15 Pro') | ||
| 105 | + (cd src/pythonnative/templates/android_template && ./gradlew :pythonnative:testDebugUnitTest) | ||
| 97 | 106 | ``` | |
| 98 | 107 | ||
| 99 | 108 | ## Conventional Commits | |
@@ -132,24 +141,27 @@ Recommended scopes (choose the smallest, most accurate unit; prefer module/direc | |||
| 132 | 141 | - Module/directory scopes: | |
| 133 | 142 | - `alerts`: imperative Alert/Picker helpers (`alerts.py`) | |
| 134 | 143 | - `animated`: Animated namespace and animation primitives (`animated.py`) | |
| 144 | + - `bootstrap`: on-device runtime start-up called by the templates (`bootstrap.py`) | ||
| 145 | + - `bridge`: wire codec, transports, handshake, and native-to-Python callback (`bridge/`) | ||
| 135 | 146 | - `cli`: CLI tool and `pn` command (`src/pythonnative/cli/`) | |
| 136 | 147 | - `component`: the `@component` decorator, `Component`, and `memo` (`component.py`) | |
| 137 | 148 | - `components`: declarative element-creating functions (`components/`) | |
| 138 | 149 | - `element`: Element descriptor class (`element.py`) | |
| 139 | 150 | - `events`: tag-based event routing between native views and Python callbacks (`events.py`) | |
| 140 | 151 | - `gestures`: gesture descriptors and the pure-Python recognition arbiter (`gestures.py`) | |
| 141 | 152 | - `hooks`: hooks and contexts (`hooks.py`) | |
| 142 | - - `hosts`: screen hosts, native lifecycle bridge, and render scheduling (`hosts/`) | ||
| 153 | + - `hosts`: screen hosts, lifecycle forwarding, and render scheduling (`hosts/`) | ||
| 143 | 154 | - `hot_reload`: file watcher and module reloader (`hot_reload.py`) | |
| 144 | 155 | - `layout`: pure-Python flexbox engine (`layout.py`) | |
| 145 | 156 | - `mutations`: batched mutation ops between reconciler and native backends (`mutations.py`) | |
| 146 | - - `native_modules`: native API modules for device capabilities (`native_modules/`) | ||
| 147 | - - `native_views`: platform-specific native view creation and updates (`native_views/`) | ||
| 157 | + - `native_modules`: native module registry, Python facades, and desktop implementations (`native_modules/`) | ||
| 158 | + - `native_views`: view registry protocol, bridge backend, and desktop handlers (`native_views/`) | ||
| 148 | 159 | - `navigation`: navigation state, container, navigators, hooks, and linking (`navigation/`) | |
| 149 | 160 | - `net`: awaitable HTTP client (`net.py`) | |
| 150 | 161 | - `package`: `src/pythonnative/__init__.py` exports and package boundary | |
| 151 | 162 | - `platform`: `Platform.OS`/`Platform.select` and version detection (`platform.py`) | |
| 152 | 163 | - `platform_metrics`: platform-reported metrics like safe-area insets and bar heights (`platform_metrics.py`) | |
| 164 | + - `project`: `pythonnative.toml` config, template configurators, plugin staging, and the builder (`project/`) | ||
| 153 | 165 | - `reconciler`: virtual view tree diffing, boundaries, and the layout pass (`reconciler/`) | |
| 154 | 166 | - `runtime`: framework-wide asyncio loop and thread-safe future helpers (`runtime.py`) | |
| 155 | 167 | - `sdk`: public extension SDK for custom native components (`sdk/`) | |
@@ -167,6 +179,8 @@ Recommended scopes (choose the smallest, most accurate unit; prefer module/direc | |||
| 167 | 179 | - `repo`: repository metadata and top‑level files (`README.md`, `CONTRIBUTING.md`, `.gitignore`, licenses) | |
| 168 | 180 | - `scripts`: developer scripts under `scripts/` (e.g., `check.sh`) | |
| 169 | 181 | - `templates`: Android/iOS project templates under `src/pythonnative/templates/` | |
| 182 | + - `kit`: the Swift rendering core (`templates/ios_template/PythonNativeKit/`) | ||
| 183 | + - `runtime-android`: the Kotlin rendering core (`templates/android_template/pythonnative/`) | ||
| 170 | 184 | - `tests`: unit/integration/E2E tests under `tests/` | |
| 171 | 185 | - `workflows`: CI pipelines under `.github/workflows/` | |
| 172 | 186 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -26,7 +26,7 @@ | |||
| 26 | 26 | ||
| 27 | 27 | ## Overview | |
| 28 | 28 | ||
| 29 | - PythonNative is a cross-platform toolkit for building native Android and iOS apps in Python. It provides a **declarative, React-like component model** with hooks and automatic reconciliation, powered by Chaquopy on Android and rubicon-objc on iOS. Write function components with `use_state`, `use_effect`, and friends, just like React, and let PythonNative handle creating and updating native views. | ||
| 29 | + PythonNative is a cross-platform toolkit for building native Android and iOS apps in Python. It provides a **declarative, React-like component model** with hooks and automatic reconciliation on top of a **native rendering core** written in Swift and Kotlin. Write function components with `use_state`, `use_effect`, and friends, just like React, and let PythonNative handle creating and updating native views. | ||
| 30 | 30 | ||
| 31 | 31 | ## Features | |
| 32 | 32 | ||
@@ -42,7 +42,7 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app | |||
| 42 | 42 | - **Native-driven animations:** The `Animated` API (timing / spring / decay / loop / stagger, awaitable or fire-and-forget) hands animations to Core Animation and `ViewPropertyAnimator` whenever possible, so no Python code runs per frame; a pure-Python ticker covers the rest. `interpolate`, arithmetic operators on animated nodes, `Animated.event` scroll binding, and `diff_clamp` cover the scroll-driven patterns (collapsing headers, parallax) that define native feel. | |
| 43 | 43 | - **Native gesture system:** Attach `Tap`, `LongPress`, `Pan`, `Swipe`, `Fling`, `Pinch`, and `Rotation` recognizers to any view via the `gestures=` prop, backed by `UIGestureRecognizer` on iOS and a unit-testable pure-Python arbiter on Android and desktop. Compose them with `Race`, `Exclusive`, and `Simultaneous` for cross-gesture arbitration (single vs. double tap, drag vs. long press). | |
| 44 | 44 | - **Virtualized lists:** `FlatList` / `SectionList` window their rows in Python over the platform scroll view: uniform, exact, or measured variable heights, grids, headers/footers, infinite scroll, and an imperative scroll controller, identical on every platform. | |
| 45 | - - **Direct native bindings:** Python calls platform APIs directly through Chaquopy and rubicon-objc, with no JavaScript bridge. | ||
| 45 | + - **Native rendering core:** each commit is one serialized transaction applied by Swift and Kotlin component managers, the same shape as React Native's Fabric. Device APIs are native modules registered by name (TurboModules-style), callable from thin Python facades. | ||
| 46 | 46 | - **Custom-component SDK:** Wrap any platform widget as a first-class element with type-checked props via `pythonnative.sdk` (`Props`, `@native_component`, `element_factory`). Plugins distributed on PyPI auto-register through the `pythonnative.handlers` entry-point group. | |
| 47 | 47 | - **CLI scaffolding:** `pn init` creates a ready-to-run project; `pn run android` and `pn run ios` build and launch your app. | |
| 48 | 48 | - **Instant desktop preview:** `pn preview` renders your app in a native desktop window via Tkinter with Fast Refresh on every save: iterate on layout, state, and navigation in milliseconds without booting a simulator or device. The reconciler, hooks, layout engine, and navigation are the same code that ships to the phone. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,48 @@ | |||
| 1 | + # Bridge | ||
| 2 | + | ||
| 3 | + The Python half of the [native bridge](../concepts/bridge.md): JSON | ||
| 4 | + codec, per-platform transports, protocol handshake, main-queue posting, | ||
| 5 | + and the single callback native uses to reach Python. App code never | ||
| 6 | + calls this module directly; the | ||
| 7 | + [`BridgeBackend`][pythonnative.native_views.bridge_backend.BridgeBackend], | ||
| 8 | + [`BridgeModule`][pythonnative.native_modules.registry.BridgeModule], and | ||
| 9 | + [`NativeScreenHost`][pythonnative.hosts.native.NativeScreenHost] do. | ||
| 10 | + | ||
| 11 | + ::: pythonnative.bridge | ||
| 12 | + options: | ||
| 13 | + show_root_heading: false | ||
| 14 | + show_root_toc_entry: false | ||
| 15 | + members_order: source | ||
| 16 | + filters: ["!^_"] | ||
| 17 | + | ||
| 18 | + ## Codec | ||
| 19 | + | ||
| 20 | + ::: pythonnative.bridge.codec | ||
| 21 | + options: | ||
| 22 | + show_root_heading: false | ||
| 23 | + show_root_toc_entry: false | ||
| 24 | + members_order: source | ||
| 25 | + filters: ["!^_"] | ||
| 26 | + | ||
| 27 | + ## Fake transport (tests) | ||
| 28 | + | ||
| 29 | + ::: pythonnative.bridge.fake | ||
| 30 | + options: | ||
| 31 | + show_root_heading: false | ||
| 32 | + show_root_toc_entry: false | ||
| 33 | + members_order: source | ||
| 34 | + filters: ["!^_"] | ||
| 35 | + | ||
| 36 | + ## Bootstrap | ||
| 37 | + | ||
| 38 | + ::: pythonnative.bootstrap | ||
| 39 | + options: | ||
| 40 | + show_root_heading: false | ||
| 41 | + show_root_toc_entry: false | ||
| 42 | + members_order: source | ||
| 43 | + filters: ["!^_"] | ||
| 44 | + | ||
| 45 | + ## Next steps | ||
| 46 | + | ||
| 47 | + - Wire format and native contracts: [The native bridge](../concepts/bridge.md). | ||
| 48 | + - Bundling native plugins: [Configuration](../guides/configuration.md#plugins). | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,9 +7,12 @@ pause, back press, destroy) to navigators and effects. It's also the | |||
| 7 | 7 | [`Stack.Navigator`][pythonnative.create_stack_navigator] talks to when | |
| 8 | 8 | it pushes real native screens. | |
| 9 | 9 | ||
| 10 | - The bundled Android (`ScreenFragment`) and iOS (`ViewController`) | ||
| 11 | - templates create a host via [`create_screen`][pythonnative.create_screen] | ||
| 12 | - and never need to be edited by app code. The desktop preview uses | ||
| 10 | + The bundled Android (`PNScreenFragment`) and iOS (`PNViewController`) | ||
| 11 | + templates create a host through the `Host` native module's `create` | ||
| 12 | + event and never need to be edited by app code; one | ||
| 13 | + [`NativeScreenHost`][pythonnative.hosts.native.NativeScreenHost] class | ||
| 14 | + serves both platforms because every platform-specific step goes over | ||
| 15 | + the [bridge](../concepts/bridge.md). The desktop preview uses | ||
| 13 | 16 | [`DesktopScreenHost`][pythonnative.hosts.desktop.DesktopScreenHost]. | |
| 14 | 17 | ||
| 15 | 18 | ::: pythonnative.hosts | |
@@ -30,18 +33,11 @@ and never need to be edited by app code. The desktop preview uses | |||
| 30 | 33 | ||
| 31 | 34 | ## Platform hosts | |
| 32 | 35 | ||
| 33 | - ::: pythonnative.hosts.android | ||
| 36 | + ::: pythonnative.hosts.native | ||
| 34 | 37 | options: | |
| 35 | 38 | show_root_heading: false | |
| 36 | 39 | show_root_toc_entry: false | |
| 37 | - members: ["AndroidScreenHost"] | ||
| 38 | - filters: ["!^_"] | ||
| 39 | - | ||
| 40 | - ::: pythonnative.hosts.ios | ||
| 41 | - options: | ||
| 42 | - show_root_heading: false | ||
| 43 | - show_root_toc_entry: false | ||
| 44 | - members: ["IOSScreenHost"] | ||
| 40 | + members_order: source | ||
| 45 | 41 | filters: ["!^_"] | |
| 46 | 42 | ||
| 47 | 43 | ::: pythonnative.hosts.desktop | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,16 +3,36 @@ | |||
| 3 | 3 | Cross-platform wrappers around device APIs that are not part of the | |
| 4 | 4 | view tree: camera, GPS, file I/O, notifications, clipboard, share | |
| 5 | 5 | sheet, deep links, permissions, connectivity, secure storage, battery, | |
| 6 | - haptics, and biometrics. Each module is implemented twice (once per | ||
| 7 | - platform) and dispatches at runtime based on the `IS_ANDROID` and | ||
| 8 | - `IS_IOS` flags from `pythonnative.utils`, with a safe desktop fallback. | ||
| 6 | + haptics, and biometrics. Each module is a Swift and a Kotlin class | ||
| 7 | + registered by name in the native runtime; the Python classes below are | ||
| 8 | + facades that call them through | ||
| 9 | + [`native_module`][pythonnative.native_modules.registry.native_module], | ||
| 10 | + with a Python implementation registered for the desktop and tests. | ||
| 9 | 11 | ||
| 10 | 12 | Both synchronous and coroutine APIs exist (chosen to match the | |
| 11 | 13 | platform call). For the call-site patterns, the reactive | |
| 12 | 14 | `use_app_state` / `use_net_info` hooks, and the runtime coroutines are | |
| 13 | 15 | scheduled on, see the [Native modules guide](../guides/native-modules.md) | |
| 14 | 16 | and the [Async + data guide](../guides/async.md). | |
| 15 | 17 | ||
| 18 | + ## Registry | ||
| 19 | + | ||
| 20 | + ::: pythonnative.native_modules.registry | ||
| 21 | + options: | ||
| 22 | + show_root_heading: false | ||
| 23 | + show_root_toc_entry: false | ||
| 24 | + members_order: source | ||
| 25 | + filters: ["!^_"] | ||
| 26 | + | ||
| 27 | + ## Desktop implementations | ||
| 28 | + | ||
| 29 | + ::: pythonnative.native_modules.desktop | ||
| 30 | + options: | ||
| 31 | + show_root_heading: false | ||
| 32 | + show_root_toc_entry: false | ||
| 33 | + members_order: source | ||
| 34 | + filters: ["!^_"] | ||
| 35 | + | ||
| 16 | 36 | ## Camera | |
| 17 | 37 | ||
| 18 | 38 | ::: pythonnative.native_modules.camera | |
@@ -142,3 +162,4 @@ and the [Async + data guide](../guides/async.md). | |||
| 142 | 162 | ## Next steps | |
| 143 | 163 | ||
| 144 | 164 | - See guidance and permission setup in [Native modules guide](../guides/native-modules.md). | |
| 165 | + - Write your own: [Native modules guide](../guides/native-modules.md#writing-your-own-native-module). | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments