FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

fix(assets): read bundled font faces from the APK manifest on Android · pythonnative/pythonnative@2ea6816 · GitHub

Repository navigation

Commit 2ea6816

Browse files
committed
fix(assets): read bundled font faces from the APK manifest on Android
1 parent 70a5b9b commit 2ea6816

9 files changed

Lines changed: 350 additions & 50 deletions

File tree

‎.github/workflows/e2e.yml‎

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,19 @@ jobs:
2626
needs: coverage
2727
runs-on: ubuntu-latest
2828
timeout-minutes: 30
29-
# GitHub-hosted Android emulators grow unstable after ~15 minutes of
30-
# sustained Maestro driving and start reporting "device offline" /
31-
# "device not found" mid-run (the emulator VM, not the app, dies).
32-
# The full suite reliably crosses that threshold around the ~35th
33-
# flow. Sharding the run into a few balanced groups, each on its
34-
# own freshly booted emulator, keeps every session well under the
29+
# GitHub-hosted Android emulators grow unstable after roughly ten
30+
# minutes of sustained Maestro driving and start reporting "device
31+
# offline" / "device not found" mid-run (the emulator VM, not the
32+
# app, dies). Sharding the run into a few balanced groups, each on
33+
# its own freshly booted emulator, keeps every session under the
3534
# limit, and parallelizes the Android pass as a bonus. Groups are
36-
# sized so none exceeds ~15 flows; ``components`` (28 flows after
37-
# the gesture/animated additions) crossed the ceiling at ~flow 26,
38-
# so it runs as two halves, and ``hooks`` (22 flows after the async
39-
# hook additions) now takes ~10 minutes of driving on its own, so
40-
# it gets a dedicated emulator. ``fail-fast: false`` so one shard's
41-
# failure still lets the others report.
35+
# sized so none exceeds ~12 heavy flows: ``components`` (35 flows
36+
# after the graphics additions) dropped offline at ~11.5 minutes
37+
# when split in two, so it runs as three parts; ``hooks`` (23 quick
38+
# flows, ~10 minutes of driving) gets a dedicated emulator; the
39+
# remaining categories are grouped to similar totals.
40+
# ``fail-fast: false`` so one shard's failure still lets the others
41+
# report.
4242
strategy:
4343
fail-fast: false
4444
matrix:
@@ -47,6 +47,8 @@ jobs:
4747
suites: components-a
4848
- name: components-b
4949
suites: components-b
50+
- name: components-c
51+
suites: components-c
5052
- name: hooks
5153
suites: hooks
5254
- name: nav-gestures-layout-styling
@@ -162,6 +164,8 @@ jobs:
162164
suites: components-a
163165
- name: components-b
164166
suites: components-b
167+
- name: components-c
168+
suites: components-c
165169
- name: hooks
166170
suites: hooks
167171
- name: nav-gestures-layout-styling

‎scripts/run-e2e.sh‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,12 @@ for suite in "${SUITES[@]}"; do
100100
MAESTRO_TARGETS+=("tests/e2e/ios.yaml")
101101
fi
102102
;;
103-
components|components-a|components-b|hooks|navigation|layout|styling|animations|gestures|assets|misc)
103+
components|components-a|components-b|components-c|hooks|navigation|layout|styling|animations|gestures|assets|misc)
104104
MAESTRO_TARGETS+=("tests/e2e/suites/${suite}.yaml")
105105
;;
106106
*)
107107
echo "Error: unknown suite '$suite'" >&2
108-
echo "Available suites: full, components, components-a, components-b, hooks, navigation, layout, styling, animations, gestures, assets, misc" >&2
108+
echo "Available suites: full, components, components-a, components-b, components-c, hooks, navigation, layout, styling, animations, gestures, assets, misc" >&2
109109
exit 2
110110
;;
111111
esac

‎src/pythonnative/assets/__init__.py‎

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -471,18 +471,54 @@ def _bundled_roots(*, exclude: Optional[str]) -> List[Path]:
471471

472472

473473
def font_faces() -> Tuple[FontFace, ...]:
474-
"""The font faces available from every readable assets root."""
474+
"""The font faces bundled with the app.
475+
476+
Readable roots (the dev overlay, a checkout, the iOS bundle) are
477+
scanned directly. On Android the bundled ``app/assets/`` lives inside
478+
the APK rather than on disk, so its faces come from the manifest the
479+
build wrote, read through the native ``Assets`` module.
480+
"""
475481
faces: List[FontFace] = []
476482
seen = set()
483+
484+
def add(face: FontFace) -> None:
485+
key = (face.family.lower(), face.weight, face.italic)
486+
if key not in seen:
487+
seen.add(key)
488+
faces.append(face)
489+
477490
for root in assets_roots():
478491
for face in scan(root).fonts:
479-
key = (face.family.lower(), face.weight, face.italic)
480-
if key not in seen:
481-
seen.add(key)
482-
faces.append(face)
492+
add(face)
493+
if not _bundled_roots(exclude=None):
494+
for face in _native_manifest().fonts:
495+
add(face)
483496
return tuple(faces)
484497

485498

499+
def _native_manifest() -> AssetManifest:
500+
"""The bundled manifest as the native runtime sees it, or an empty one.
501+
502+
Used when the bundle isn't a directory Python can list (Android).
503+
"""
504+
from ..bridge import has_transport
505+
506+
if not has_transport():
507+
return AssetManifest()
508+
from ..native_modules.registry import NativeModuleError, native_module
509+
510+
try:
511+
encoded = native_module("Assets").call("read", path=MANIFEST_NAME)
512+
except NativeModuleError:
513+
return AssetManifest()
514+
if not encoded:
515+
return AssetManifest()
516+
try:
517+
return AssetManifest.from_dict(json.loads(base64.b64decode(encoded)))
518+
except (ValueError, KeyError, TypeError):
519+
return AssetManifest()
520+
521+
486522
# ----------------------------------------------------------------------
487523
# Dev-time coordination with the native runtime
488524
# ----------------------------------------------------------------------

‎tests/e2e/AGENTS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ scripts/
7373
./scripts/run-e2e.sh ios components
7474
```
7575

76-
Available category suites: `components`, `hooks`, `navigation`, `layout`, `styling`, `animations`, `gestures`, `assets`, `misc`. The components category also has `components-a` / `components-b` halves: CI's Android shards use them because a GitHub-hosted emulator session degrades and drops offline before all 28 component flows finish in one run (`components.yaml` just chains the two halves).
76+
Available category suites: `components`, `hooks`, `navigation`, `layout`, `styling`, `animations`, `gestures`, `assets`, `misc`. The components category also has `components-a` / `components-b` / `components-c` parts: CI's Android shards use them because a GitHub-hosted emulator session degrades and drops offline before all 35 component flows finish in one run (`components.yaml` just chains the three parts).
7777

7878
You can also run a single flow directly. Useful when iterating on one demo:
7979

‎tests/e2e/suites/components-a.yaml‎

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# Component category suite, first half (A); see components.yaml.
1+
# Component category suite, part 1 of three; see components.yaml.
22
#
3-
# The components category is large enough (28 flows) that a single
3+
# The components category is large enough (35 flows) that a single
44
# GitHub-hosted Android emulator session can't reliably finish it: the
5-
# emulator grows unstable after ~15 minutes of sustained Maestro
6-
# driving and drops offline around the ~26th flow. CI therefore runs
7-
# the category as two halves, each on a freshly booted emulator.
5+
# emulator grows unstable after roughly ten minutes of sustained Maestro
6+
# driving and drops offline mid-flow. CI therefore runs the category as
7+
# three parts of about twelve flows, each on a freshly booted emulator.
88
#
99
# Usage:
1010
# maestro test tests/e2e/suites/components-a.yaml -e APP_ID=com.pythonnative.e2e
@@ -22,7 +22,3 @@ appId: ${APP_ID}
2222
- runFlow: ../flows/components/activity_indicator.yaml
2323
- runFlow: ../flows/components/view_column_row.yaml
2424
- runFlow: ../flows/components/scroll_view.yaml
25-
- runFlow: ../flows/components/safe_area_view.yaml
26-
- runFlow: ../flows/components/modal.yaml
27-
- runFlow: ../flows/components/pressable.yaml
28-
- runFlow: ../flows/components/picker.yaml

‎tests/e2e/suites/components-b.yaml‎

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1-
# Component category suite, second half (B); see components.yaml.
1+
# Component category suite, part 2 of three; see components.yaml.
22
#
3-
# The components category is large enough (28 flows) that a single
3+
# The components category is large enough (35 flows) that a single
44
# GitHub-hosted Android emulator session can't reliably finish it: the
5-
# emulator grows unstable after ~15 minutes of sustained Maestro
6-
# driving and drops offline around the ~26th flow. CI therefore runs
7-
# the category as two halves, each on a freshly booted emulator.
5+
# emulator grows unstable after roughly ten minutes of sustained Maestro
6+
# driving and drops offline mid-flow. CI therefore runs the category as
7+
# three parts of about twelve flows, each on a freshly booted emulator.
88
#
99
# Usage:
1010
# maestro test tests/e2e/suites/components-b.yaml -e APP_ID=com.pythonnative.e2e
1111
appId: ${APP_ID}
1212
---
13+
- runFlow: ../flows/components/safe_area_view.yaml
14+
- runFlow: ../flows/components/modal.yaml
15+
- runFlow: ../flows/components/pressable.yaml
16+
- runFlow: ../flows/components/picker.yaml
1317
- runFlow: ../flows/components/refresh_control.yaml
1418
- runFlow: ../flows/components/fragment.yaml
1519
- runFlow: ../flows/components/portal.yaml
@@ -18,14 +22,3 @@ appId: ${APP_ID}
1822
- runFlow: ../flows/components/status_bar.yaml
1923
- runFlow: ../flows/components/keyboard_avoiding_view.yaml
2024
- runFlow: ../flows/components/flat_list.yaml
21-
- runFlow: ../flows/components/section_list.yaml
22-
- runFlow: ../flows/components/web_view.yaml
23-
- runFlow: ../flows/components/touchable_opacity.yaml
24-
- runFlow: ../flows/components/image_background.yaml
25-
- runFlow: ../flows/components/linear_gradient.yaml
26-
- runFlow: ../flows/components/blur_view.yaml
27-
- runFlow: ../flows/components/checkbox.yaml
28-
- runFlow: ../flows/components/segmented_control.yaml
29-
- runFlow: ../flows/components/date_picker.yaml
30-
- runFlow: ../flows/components/suspense.yaml
31-
- runFlow: ../flows/components/lazy.yaml

‎tests/e2e/suites/components-c.yaml‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Component category suite, part 3 of three; see components.yaml.
2+
#
3+
# The components category is large enough (35 flows) that a single
4+
# GitHub-hosted Android emulator session can't reliably finish it: the
5+
# emulator grows unstable after roughly ten minutes of sustained Maestro
6+
# driving and drops offline mid-flow. CI therefore runs the category as
7+
# three parts of about twelve flows, each on a freshly booted emulator.
8+
#
9+
# Usage:
10+
# maestro test tests/e2e/suites/components-c.yaml -e APP_ID=com.pythonnative.e2e
11+
appId: ${APP_ID}
12+
---
13+
- runFlow: ../flows/components/section_list.yaml
14+
- runFlow: ../flows/components/web_view.yaml
15+
- runFlow: ../flows/components/touchable_opacity.yaml
16+
- runFlow: ../flows/components/image_background.yaml
17+
- runFlow: ../flows/components/linear_gradient.yaml
18+
- runFlow: ../flows/components/blur_view.yaml
19+
- runFlow: ../flows/components/checkbox.yaml
20+
- runFlow: ../flows/components/segmented_control.yaml
21+
- runFlow: ../flows/components/date_picker.yaml
22+
- runFlow: ../flows/components/suspense.yaml
23+
- runFlow: ../flows/components/lazy.yaml

‎tests/e2e/suites/components.yaml‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
# Useful for AI agents iterating on a component fix: only the relevant
77
# flows run, keeping the feedback loop tight.
88
#
9-
# The flow list lives in components-a.yaml and components-b.yaml; this
10-
# file just chains the halves. CI runs the halves as separate Android
11-
# shards (a GitHub-hosted emulator can't survive all 28 flows in one
12-
# session; see the half files), while iOS simulators and local runs
13-
# can use this aggregate directly.
9+
# The flow list lives in components-a.yaml, components-b.yaml, and
10+
# components-c.yaml; this file just chains the parts. CI runs the parts
11+
# as separate Android shards (a GitHub-hosted emulator can't survive all
12+
# 35 flows in one session; see the part files), while iOS simulators and
13+
# local runs can use this aggregate directly.
1414
appId: ${APP_ID}
1515
---
1616
- runFlow: components-a.yaml
1717
- runFlow: components-b.yaml
18+
- runFlow: components-c.yaml

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL