Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
80be4b5
Python support: transpiler, runtime, stdlib and native benchmark gate
shai-almog Oct 27, 2026
f484312
Python: Java interop, project import and build integration
shai-almog Oct 27, 2026
1751179
Python: UI sample, project integration test and java.* against the de…
shai-almog Oct 27, 2026
f53f018
Python: site package root beside the stdlib
shai-almog Oct 27, 2026
b7f26b0
Python: requests and httpx over the platform HTTP client
shai-almog Oct 27, 2026
abbfa76
Python: runtime generic aliases and unions, string annotations in get…
shai-almog Oct 27, 2026
23bdc60
Python: PyYAML package
shai-almog Oct 27, 2026
f222550
Python: attrs and dateutil packages
shai-almog Oct 27, 2026
0eed8b7
Python: pydantic package
shai-almog Oct 27, 2026
b82eaee
Python: numpy subset over Java kernels, relative submodule imports, s…
shai-almog Oct 27, 2026
0647330
Python: evaluated call and lambda annotations, inspect, __code__, mod…
shai-almog Oct 27, 2026
16dfcfc
Python: native backend server through vm/backend's HttpServer
shai-almog Oct 27, 2026
66b376d
Python: typing_extensions, six, tomllib
shai-almog Oct 27, 2026
a478550
Python: tabulate
shai-almog Oct 27, 2026
6128984
Python: idna and packaging site packages
shai-almog Oct 27, 2026
b76c774
Python: Flask and FastAPI over a pure dispatch core
shai-almog Oct 27, 2026
9c6462d
Python: co_flags marks generator, coroutine and async generator funct…
shai-almog Oct 27, 2026
04f235d
Python: Flask sample, CPython/PyPy comparison and developer guide cha…
shai-almog Oct 27, 2026
1e33bef
Python: runtime and transpiler at zero SpotBugs, PMD and Checkstyle f…
shai-almog Oct 27, 2026
8ef35f8
Python: typed math, slots classes, annotated locals and per-call-site…
shai-almog Oct 27, 2026
a6aa20a
Python: GraalPy in every comparison, CommonWorkloads with RSS, perfor…
shai-almog Oct 27, 2026
448ee65
Python: drop fully qualified Set in Infer (PMD)
shai-almog Oct 27, 2026
8d78702
Python: hold provably bounded ints in Java longs
shai-almog Oct 27, 2026
6642220
Python: scalar-replace non-escaping objects, typed str loops, int % a…
shai-almog Oct 27, 2026
d0611f5
Python: branch/loop-test int range refinement, threshold widening, ty…
shai-almog Oct 27, 2026
537976b
Python: long-parameter function versions from call-site ranges; typed…
shai-almog Oct 28, 2026
2aa2d04
Python: one-new construction for plain __init__, no default shape/slo…
shai-almog Oct 28, 2026
89021bb
Python: str + chains into one presized StringBuilder; hoist statement…
shai-almog Oct 28, 2026
292091f
Python: int-keyed dict get/set without boxing the lookup key; bulk di…
shai-almog Oct 28, 2026
8b2f406
Python: int lists hold 32-bit items, as Java's int[] does; wider ints…
shai-almog Oct 28, 2026
1c4dc1d
Python: math.sqrt/sin/cos/fmod domain checks in line, Math called dir…
shai-almog Oct 28, 2026
b9c5597
Python: compare against Codename One Java; startup, kernel and Flask …
shai-almog Oct 28, 2026
78f3c4a
Python: classes report the Python file and lines to stack traces and …
shai-almog Oct 28, 2026
a4d0208
Python: sqlite3 over Codename One's Database; rows report SQLite stor…
shai-almog Oct 28, 2026
79525b9
Python: unittest (TestCase, suites, loader, runner, mock/patch) and a…
shai-almog Oct 28, 2026
904ff0c
Python: threading, a blocking queue and concurrent.futures over Java …
shai-almog Oct 28, 2026
cf4b92e
Python: pickle (protocols 0-5, byte-compatible with CPython), copyreg…
shai-almog Oct 28, 2026
7958276
Python: urllib.request, urllib.error, http.client and http.HTTPStatus…
shai-almog Oct 28, 2026
80c452e
Python: zlib over JZlib, gzip, zipfile, stat, zoneinfo over the platf…
shai-almog Oct 28, 2026
1c7efad
Python: resolve PyPI requirements on import and replace C extension m…
shai-almog Oct 28, 2026
447fe29
Python: split the static-field getter per class so importing FontImag…
shai-almog Oct 28, 2026
766820c
Python guide: user interface examples, PyPI packages, C extensions, t…
shai-almog Oct 28, 2026
723b12d
Python: range attributes and equality, builtins module names, __setat…
shai-almog Oct 28, 2026
c868ce5
Python: Flask sessions, Jinja templates, multipart uploads and stream…
shai-almog Oct 28, 2026
57b8c48
Python guide: Flask sessions, templates, uploads and streaming
shai-almog Oct 28, 2026
758edcb
Python: Pillow subset (PIL.Image, ImageDraw, ImageOps, ImageFilter.Bo…
shai-almog Oct 28, 2026
026029d
Python guide: Pillow subset
shai-almog Oct 28, 2026
e92e3ce
Python: pandas subset (Series, DataFrame, groupby, merge, concat, CSV…
shai-almog Oct 28, 2026
b5d6be2
Python guide: pandas subset
shai-almog Oct 28, 2026
6a6ad35
Python: FastAPI middleware (http, CORS, GZip, TrustedHost, BaseHTTPMi…
shai-almog Oct 28, 2026
f9233fa
Python guide: FastAPI middleware and WebSockets
shai-almog Oct 28, 2026
3dbe16f
Python: SQLAlchemy 2.x subset (Core + declarative ORM over sqlite3)
shai-almog Oct 28, 2026
0710068
Python: WebSocket endpoints run on a real asyncio loop, through middl…
shai-almog Oct 28, 2026
20a146e
Python: SQLAlchemy relationships, eager loading, inheritance and subq…
shai-almog Oct 28, 2026
88d45c9
Backend: refuse a websocket upgrade with any status, add 101 headers;…
shai-almog Oct 28, 2026
ef7298d
Python: typing.ForwardRef, and SQLAlchemy PostgreSQL/MySQL/MariaDB di…
shai-almog Oct 28, 2026
a3a4485
Python backend: end-to-end server test, true streaming, GIL release i…
shai-almog Oct 28, 2026
27576bf
Guide: Python WebSockets run on asyncio, streams are chunked
shai-almog Oct 28, 2026
9dac7de
Python: run the SQLAlchemy conformance programs against real PostgreS…
shai-almog Oct 28, 2026
b88bc79
Python backend: serve requests concurrently, run background tasks aft…
shai-almog Oct 28, 2026
a8ce938
Python SQLAlchemy on real PostgreSQL: aliased self join, Decimal, err…
shai-almog Oct 28, 2026
8c72263
Guide: SQLAlchemy section, its example held by a conformance program
shai-almog Oct 28, 2026
6b57f2c
Python: itsdangerous-compatible Flask session cookies, Jinja macros/c…
shai-almog Oct 28, 2026
cd52796
Guide: Flask sessions interoperate with CPython, Jinja macros
shai-almog Oct 28, 2026
a35ecee
Python: virtual-thread-safe GIL, engine-neutral SQLAlchemy inspect, S…
shai-almog Oct 28, 2026
750a2ab
Python: Pillow BOX/HAMMING/BICUBIC/LANCZOS resampling, bitmap-font te…
shai-almog Oct 28, 2026
330d9c2
Guide: Pillow modes, filters and text; pandas shortened printing
shai-almog Oct 28, 2026
7d6813d
Python: __getattribute__ sees dunder reads, object reduce protocol dr…
shai-almog Oct 28, 2026
d2d600b
Python: a program that calls object.__reduce_ex__ without importing c…
shai-almog Oct 28, 2026
59bb46a
Python runtime: clear PMD findings
shai-almog Oct 28, 2026
2eeb9ec
Python backend: native e2e (--native), PIL codec out of the server bu…
shai-almog Oct 28, 2026
b6f9578
Backend SQL: sslmode=verify-ca/verify-full and MySQL's ssl-mode/ssl-c…
shai-almog Oct 28, 2026
2fd7aaf
SQLAlchemy subset on MySQL: type_annotation_map, RETURNING refused at…
shai-almog Oct 28, 2026
7b10fa7
Shared pure-Java image API (com.codename1.image) for devices and serv…
shai-almog Oct 28, 2026
1316815
Core: drop a redundant qualified name
shai-almog Oct 28, 2026
fc25720
Python SQLAlchemy: Session compiles for its bind's dialect; typed DEC…
shai-almog Oct 28, 2026
e1ff790
python-runtime: exclude PySql.Result.types from UWF (written by the g…
shai-almog Oct 28, 2026
ea628bb
Backend: @VirtualThreadStack and the python.virtualThreadStack build …
shai-almog Oct 28, 2026
98c30a6
Docs: database TLS modes, typed columns, virtual-thread stack size
shai-almog Oct 28, 2026
abeed31
TrueTypeFont: pure-Java TrueType fonts for com.codename1.image, embed…
shai-almog Oct 28, 2026
6a0ba99
Guide: Pillow reads and writes JPEG on servers, TrueType text
shai-almog Oct 28, 2026
195ddbe
Image API moves to the backend (com.codename1.backend.image); Pillow …
shai-almog Oct 28, 2026
8610361
Pillow client engine: headless conformance run of PyImageNative; e2e …
shai-almog Oct 28, 2026
0da25db
Font.createTrueTypeFontFromData: TrueType/OpenType fonts from a strea…
shai-almog Oct 28, 2026
20a7cab
Linux/Windows createTrueTypeFontFromData: null for bytes without an S…
shai-almog Oct 28, 2026
320b57b
JavaScript createTrueTypeFontFromData: null for bytes without an SFNT…
shai-almog Oct 28, 2026
dbca9a2
Column types cached per row; data fonts keyed by content; font loader…
shai-almog Oct 28, 2026
9a6c102
Backend: sslmode in TLS errors, timetz kind, case-insensitive header …
shai-almog Oct 28, 2026
aabd6dd
Python runtime: lock-free locks and websocket handshake, fair GIL yie…
shai-almog Oct 28, 2026
bd6d027
Column-type capture before reads only for the iOS cursor; Windows rep…
shai-almog Oct 28, 2026
5fb4edd
Backend: stack-raise latch counts live bound servers; TLS errors name…
shai-almog Oct 28, 2026
fa4eb62
HttpServer: an abandoned start gives back its live-server count
shai-almog Oct 28, 2026
9753835
Python runtime: round-2 red-team fixes and driver/websocket tests
shai-almog Oct 28, 2026
214540b
Python runtime: round-3 red-team fixes
shai-almog Oct 28, 2026
c19617a
Inflate decodes a stream's last short code; one __dict__ view per ins…
shai-almog Oct 28, 2026
a098e0b
Python: len() on a dict view syncs before answering
shai-almog Oct 28, 2026
982eccb
TrueTypeFontFromDataTest: icon glyphs as unicode escapes (ASCII-only …
shai-almog Oct 28, 2026
434f233
Merge remote-tracking branch 'origin/master' into python-support
shai-almog Oct 28, 2026
7f80a3a
PR review: CI paths for the hostfs shims and the core, version-free b…
shai-almog Oct 29, 2026
811f263
Guide name check reads Python sources too (starlette's TestClient is …
shai-almog Oct 29, 2026
1552509
python-bench: packages read, so the job can pull the CI container
shai-almog Oct 29, 2026
9bc2900
Copyright headers: full header on three test files; drop the .py excl…
shai-almog Oct 29, 2026
3adbb23
Port status: TrueTypeFontFromDataTest belongs to text and image drawing
shai-almog Oct 29, 2026
60a9c54
python-bench: install the transpiler's test dependencies before the J…
shai-almog Oct 29, 2026
270df5d
Guide: prose flags, self-contained font snippets, server snippets mar…
shai-almog Oct 29, 2026
37b4369
CodeQL: bound sdist tar entry sizes, possessive import regex; archety…
shai-almog Oct 29, 2026
af8d149
Backend SelfTest: verify-full, verify-ca and VERIFY_IDENTITY are impl…
shai-almog Oct 29, 2026
dac2e3a
PMD is zero-findings now: python-transpiler's five findings fixed or …
shai-almog Oct 29, 2026
994a49b
Android: loadTrueTypeFontFromData answers null for bytes that are not…
shai-almog Oct 29, 2026
9ac01d9
Python: str case and classes from CPython's tables; native conformanc…
shai-almog Oct 29, 2026
9ebc177
Merge remote-tracking branch 'origin/master' into python-support
shai-almog Oct 29, 2026
6d9e3cf
Merge origin/master; zoneinfo keys from a table, iOS font-from-data m…
shai-almog Oct 30, 2026
3184a6a
Python benchmark: pin the jvm job to ubuntu-24.04, where CPython 3.13…
shai-almog Oct 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 4 additions & 3 deletions .github/workflows/developer-guide-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,12 @@ jobs:
# Through retry.sh, transient failures only, like the demo install below:
# this is the step that resolves the most from Central, and a single 502
# on a plugin dependency (maven-shared-utils) failed the whole guide build.
# dart-runtime and flutter-runtime: docs/demos/common depends on the Flutter
# runtime at this version, which nothing else selected here pulls in; they are
# dart-runtime, flutter-runtime and python-runtime: docs/demos/common depends on
# the Flutter and Python runtimes at this version, which nothing else selected
# here pulls in; they are
# in the reactor because this job runs on JDK 17 (the flutter-modules profile).
RETRY_ONLY_MATCHING=transient xvfb-run -a bash scripts/ci/retry.sh mvn -B -ntp -f maven/pom.xml \
-pl core,javase,android,css-compiler,codenameone-maven-plugin,backend,backend-test,dart-runtime,flutter-runtime \
-pl core,javase,android,css-compiler,codenameone-maven-plugin,backend,backend-test,dart-runtime,flutter-runtime,python-runtime \
-am install \
-Plocal-dev-javase \
-DskipTests \
Expand Down
59 changes: 59 additions & 0 deletions .github/workflows/parparvm-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ on:
- 'maven/project-model/**'
- 'maven/backend/**'
- 'maven/backend-test/**'
# The Python SQLAlchemy step runs these against the PostgreSQL service.
- 'maven/python-runtime/**'
- 'maven/python-transpiler/**'
- 'scripts/python-backend/sqlalchemy-realdb-test.sh'
- 'scripts/python-backend/build.sh'
- 'scripts/python-backend/e2e-test.sh'
- 'scripts/python-backend/e2e_client.py'
- 'scripts/python-backend/samples/**'
# sqlalchemy-realdb-test.sh compiles the host file system shims from here.
- 'scripts/python-bench/hostfs/**'
- 'scripts/hellocodenameone/pom.xml'
- 'scripts/hellocodenameone/backend/**'
# The core classes the backend compiles as its own (the ORM and the entity
Expand Down Expand Up @@ -120,6 +130,16 @@ on:
- 'maven/project-model/**'
- 'maven/backend/**'
- 'maven/backend-test/**'
# The Python SQLAlchemy step runs these against the PostgreSQL service.
- 'maven/python-runtime/**'
- 'maven/python-transpiler/**'
- 'scripts/python-backend/sqlalchemy-realdb-test.sh'
- 'scripts/python-backend/build.sh'
- 'scripts/python-backend/e2e-test.sh'
- 'scripts/python-backend/e2e_client.py'
- 'scripts/python-backend/samples/**'
# sqlalchemy-realdb-test.sh compiles the host file system shims from here.
- 'scripts/python-bench/hostfs/**'
- 'scripts/hellocodenameone/pom.xml'
- 'scripts/hellocodenameone/backend/**'
# The core classes the backend compiles as its own (the ORM and the entity
Expand Down Expand Up @@ -492,6 +512,45 @@ jobs:
# the step above just installed from this same checkout.
CN1SS_BACKEND_SKIP_INSTALL: 1

# The SQLAlchemy conformance programs against the PostgreSQL service
# above: the suite in python-transpiler runs them on SQLite only, so this
# is the one place the postgresql dialect and the _cn1db bridge meet a
# real server. PostgreSQL and the job's MySQL service; MariaDB is run by
# hand. Last of the steps using MySQL: each program drops and recreates
# the cn1 database.
# python-runtime compiles at release 17, hence JDK 17 for the install.
- name: Python SQLAlchemy on PostgreSQL and MySQL
run: |
(cd maven && bash "$GITHUB_WORKSPACE/scripts/ci/retry.sh" mvn -B -pl python-runtime,python-transpiler \
install -DskipTests -Dspotbugs.skip=true -Dpmd.skip=true -Dcheckstyle.skip=true \
-Dmaven.javadoc.skip=true -Dmaven.repo.local="$GITHUB_WORKSPACE/.m2-repo")
# The test transpiles against JavaAPI from the same repository, and
# the step that installs it for the native samples runs after this.
bash "$GITHUB_WORKSPACE/scripts/ci/retry.sh" mvn -B -f vm/pom.xml -pl JavaAPI install -DskipTests \
-Dmaven.repo.local="$GITHUB_WORKSPACE/.m2-repo"
bash scripts/python-backend/sqlalchemy-realdb-test.sh "$GITHUB_WORKSPACE/.m2-repo"
env:
JAVA_HOME: ${{ env.JDK_17_HOME }}
JAVA17_HOME: ${{ env.JDK_17_HOME }}
CN1_SQLA_POSTGRES: postgres://cn1:cn1secret@127.0.0.1:5432/cn1?sslmode=disable
CN1_SQLA_MYSQL: mysql://cn1:cn1secret@127.0.0.1:3306/cn1?sslmode=disable

# The Flask and FastAPI samples built NATIVELY (ParparVM, clang) and
# driven over sockets by the same client as the JVM run. The only place
# Python handlers run on the backend's virtual threads, so the only run
# of the GIL's scheduler path. python-transpiler and python-runtime were
# installed by the step above; core, backend and build-engine by the
# contract install; JavaAPI explicitly, since the JVM tests may not.
- name: Python backend end to end, native
run: |
bash "$GITHUB_WORKSPACE/scripts/ci/retry.sh" mvn -B -f vm/pom.xml -pl JavaAPI install -DskipTests \
-Dmaven.repo.local="$GITHUB_WORKSPACE/.m2-repo"
bash scripts/python-backend/e2e-test.sh --native "$GITHUB_WORKSPACE/.m2-repo"
env:
JAVA_HOME: ${{ env.JDK_8_HOME }}
JDK_8_HOME: ${{ env.JDK_8_HOME }}
JAVA17_HOME: ${{ env.JDK_17_HOME }}

- name: Run ParparVM Benchmark
working-directory: vm
# Each benchmark already creates its own mutator/collector threads. Run
Expand Down
26 changes: 17 additions & 9 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,15 @@ jobs:
-Dcn1.binaries="${CN1_BINARIES}" \
-Pcompile-android \
-DbackendAnalysis \
-pl android,ios,project-model,build-engine,codenameone-maven-plugin,codenameone-gradle-plugin,backend,backend-test,backend-parparvm,javac,android-res-compiler,android-compat,swing-compat,javafx-compat,compose-compat,fxml-compiler,desktop-compat-runtime -am verify
-pl android,ios,project-model,build-engine,codenameone-maven-plugin,codenameone-gradle-plugin,backend,backend-test,backend-parparvm,javac,android-res-compiler,android-compat,swing-compat,javafx-compat,compose-compat,fxml-compiler,desktop-compat-runtime,python-transpiler -am verify
# The Python runtime compiles at release 17, so it cannot join the JDK 8
# reactor above; it runs against the core that reactor installed. It ships
# inside applications, so it is held to the same zero-findings gate.
- name: Run SpotBugs for the Python runtime
if: ${{ matrix.java-version == 8 }}
working-directory: maven
run: |
JAVA_HOME="${JAVA_HOME_17}" mvn -B -DskipTests=true -Pflutter-modules -pl python-runtime verify
- name: Type-check the SQLCipher-backed database package
if: ${{ matrix.java-version == 8 }}
env:
Expand Down Expand Up @@ -620,7 +628,7 @@ jobs:
- name: Generate static analysis HTML summaries
if: ${{ !cancelled() && matrix.java-version == 8 }}
env:
QUALITY_REPORT_TARGET_DIRS: maven/core-unittests/target:maven/android/target:maven/ios/target:vm/ByteCodeTranslator/target:maven/codenameone-maven-plugin/target:maven/build-engine/target:maven/project-model/target:maven/codenameone-gradle-plugin/target:maven/build-hint-catalog/target:maven/build-hint-tools/target:maven/backend/target:maven/backend-test/target:maven/backend-parparvm/target:maven/javac/target:maven/android-res-compiler/target:maven/android-compat/target:maven/swing-compat/target:maven/javafx-compat/target:maven/compose-compat/target:maven/fxml-compiler/target:maven/desktop-compat-runtime/target
QUALITY_REPORT_TARGET_DIRS: maven/core-unittests/target:maven/android/target:maven/ios/target:vm/ByteCodeTranslator/target:maven/codenameone-maven-plugin/target:maven/build-engine/target:maven/project-model/target:maven/codenameone-gradle-plugin/target:maven/build-hint-catalog/target:maven/build-hint-tools/target:maven/backend/target:maven/backend-test/target:maven/backend-parparvm/target:maven/javac/target:maven/android-res-compiler/target:maven/android-compat/target:maven/swing-compat/target:maven/javafx-compat/target:maven/compose-compat/target:maven/fxml-compiler/target:maven/desktop-compat-runtime/target:maven/python-transpiler/target:maven/python-runtime/target
QUALITY_REPORT_SERVER_URL: ${{ github.server_url }}
QUALITY_REPORT_REPOSITORY: ${{ github.repository }}
QUALITY_REPORT_REF: ${{ github.event.pull_request.head.sha || github.sha }}
Expand Down Expand Up @@ -777,16 +785,16 @@ jobs:
- name: Generate quality report summary
if: ${{ !cancelled() && matrix.java-version == 8 }}
env:
QUALITY_REPORT_TARGET_DIRS: maven/core-unittests/target:maven/android/target:maven/ios/target:vm/ByteCodeTranslator/target:maven/codenameone-maven-plugin/target:maven/build-engine/target:maven/project-model/target:maven/codenameone-gradle-plugin/target:maven/build-hint-catalog/target:maven/build-hint-tools/target:maven/backend/target:maven/backend-test/target:maven/backend-parparvm/target:maven/javac/target:maven/android-res-compiler/target:maven/android-compat/target:maven/swing-compat/target:maven/javafx-compat/target:maven/compose-compat/target:maven/fxml-compiler/target:maven/desktop-compat-runtime/target
QUALITY_REPORT_TARGET_DIRS: maven/core-unittests/target:maven/android/target:maven/ios/target:vm/ByteCodeTranslator/target:maven/codenameone-maven-plugin/target:maven/build-engine/target:maven/project-model/target:maven/codenameone-gradle-plugin/target:maven/build-hint-catalog/target:maven/build-hint-tools/target:maven/backend/target:maven/backend-test/target:maven/backend-parparvm/target:maven/javac/target:maven/android-res-compiler/target:maven/android-compat/target:maven/swing-compat/target:maven/javafx-compat/target:maven/compose-compat/target:maven/fxml-compiler/target:maven/desktop-compat-runtime/target:maven/python-transpiler/target:maven/python-runtime/target
# Every project listed here must produce a SpotBugs report and that
# report must be empty. A missing report fails the gate too, so a
# SpotBugs run that silently stops running is not mistaken for clean.
QUALITY_REPORT_REQUIRED_SPOTBUGS: core-unittests:android:ios:ByteCodeTranslator:codenameone-maven-plugin:build-engine:project-model:codenameone-gradle-plugin:build-hint-catalog:build-hint-tools:backend:backend-test:javac:android-res-compiler:android-compat:swing-compat:javafx-compat:compose-compat:fxml-compiler:desktop-compat-runtime
# PMD and Checkstyle run on the core and on the backend runtime, and each
# must produce its report: without one, the PMD gate below it
# has nothing to read and passes.
QUALITY_REPORT_REQUIRED_PMD: core-unittests:backend:backend-test:backend-parparvm
QUALITY_REPORT_REQUIRED_CHECKSTYLE: core-unittests:backend:backend-test
QUALITY_REPORT_REQUIRED_SPOTBUGS: core-unittests:android:ios:ByteCodeTranslator:codenameone-maven-plugin:build-engine:project-model:codenameone-gradle-plugin:build-hint-catalog:build-hint-tools:backend:backend-test:javac:android-res-compiler:android-compat:swing-compat:javafx-compat:compose-compat:fxml-compiler:desktop-compat-runtime:python-transpiler:python-runtime
# PMD and Checkstyle run on the core, the backend runtime and the Python
# transpiler and runtime, and each must produce its report: without one,
# the PMD gate below it has nothing to read and passes.
QUALITY_REPORT_REQUIRED_PMD: core-unittests:backend:backend-test:backend-parparvm:python-transpiler:python-runtime
QUALITY_REPORT_REQUIRED_CHECKSTYLE: core-unittests:backend:backend-test:python-transpiler:python-runtime
QUALITY_REPORT_SERVER_URL: ${{ github.server_url }}
QUALITY_REPORT_REPOSITORY: ${{ github.repository }}
QUALITY_REPORT_REF: ${{ github.event.pull_request.head.sha || github.sha }}
Expand Down
204 changes: 204 additions & 0 deletions .github/workflows/python-bench.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
name: Python benchmark

# Runs the kernels in scripts/python-bench/kernels twice -- by CPython and
# transpiled to Java by Codename One -- checks that both compute the same
# result, and gates the ours/CPython ratio of compute time, process wall time
# and peak memory against scripts/python-bench/baseline/ratios.json.
#
# Two arms: the JVM (the simulator and desktop targets) and ParparVM (the
# native translation iOS and the native desktop targets ship), each gated on
# its own baseline. The ParparVM arm also runs the conformance programs as
# native executables, where a bad cast is a crash rather than an exception.
# Android and JavaScript join as the Python support grows.
#
# It also runs the transpiler's conformance tests, which need the Java 17
# runtime and so cannot run in pr.yml's JDK 8 reactor.

on:
pull_request:
paths:
- 'maven/python-transpiler/**'
- 'maven/python-runtime/**'
- 'scripts/python-bench/**'
- '.github/workflows/python-bench.yml'
# The ParparVM arm translates and compiles with these.
- 'vm/ByteCodeTranslator/**'
- 'vm/JavaAPI/**'
- 'vm/selfhost/compile-dist.sh'
# Transpiled Python runs on the core's classes (collections, io/gzip).
- 'CodenameOne/src/**'
- 'maven/core/**'
- 'maven/pom.xml'
workflow_dispatch:

permissions:
contents: read
# The pr-ci-container image lives on ghcr; without this the job dies in
# "Initialize containers" with a bare "denied".
packages: read

env:
# Pinned, like flutter-bench's FLUTTER_REF: the ratios are against this
# interpreter, and moving it is a deliberate re-baseline.
CPYTHON_VERSION: '3.13.9'

jobs:
# JDK 8 for the core (the container bakes both JDKs and cn1-binaries, as
# flutter-bench's framework job explains), JDK 17 for the runtime.
framework:
name: framework
runs-on: ubuntu-latest
container: ghcr.io/codenameone/codenameone/pr-ci-container:latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v4

- name: Link cn1-binaries
run: ln -s /opt/cn1-binaries ../cn1-binaries

# compat-testing and backend are the transpiler's test dependencies
# (the pilclient_ and pil_ conformance programs); the JDK 17 step
# below runs without -am, so they have to be installed here.
- name: Build the core and the transpiler on JDK 8
run: |
cd maven
JAVA_HOME="$JAVA_HOME_8" bash ../scripts/ci/retry.sh mvn -B -q install -DskipTests \
-Dmaven.javadoc.skip=true -Dmaven.source.skip=true \
-Dmaven.repo.local="$GITHUB_WORKSPACE/m2" \
-pl core,python-transpiler,compat-testing,backend -am

# Without -am: core was installed above, and re-resolving it here would
# rebuild it on the wrong JDK.
- name: Build the runtime and run the conformance tests on JDK 17
run: |
cd maven
JAVA_HOME="$JAVA_HOME_17" bash ../scripts/ci/retry.sh mvn -B install \
-Dmaven.javadoc.skip=true -Dmaven.source.skip=true \
-Dmaven.repo.local="$GITHUB_WORKSPACE/m2" \
-pl python-runtime,python-transpiler

- name: Build the ParparVM translator and its class library on JDK 8
run: |
JAVA_HOME="$JAVA_HOME_8" bash scripts/ci/retry.sh mvn -B -q install -DskipTests \
-Dmaven.javadoc.skip=true -Dmaven.source.skip=true \
-Dmaven.repo.local="$GITHUB_WORKSPACE/m2" \
-f vm/pom.xml -pl JavaAPI,ByteCodeTranslator -am

- name: Pack the repository
run: tar -C "$GITHUB_WORKSPACE" -czf framework-m2.tgz m2

- name: Upload the repository
uses: actions/upload-artifact@v4
with:
name: python-bench-framework
path: framework-m2.tgz
retention-days: 1

measure:
name: jvm
needs: framework
# Pinned: setup-python has no CPYTHON_VERSION build for ubuntu-latest
# (26.04), and the baselines are measured against that exact version.
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17

- name: Set up CPython
uses: actions/setup-python@v5
with:
python-version: ${{ env.CPYTHON_VERSION }}

- name: Download the framework
uses: actions/download-artifact@v4
with:
name: python-bench-framework

- name: Unpack the framework
run: tar -xzf framework-m2.tgz

- name: Measure and gate
run: |
repo="$GITHUB_WORKSPACE/m2/com/codenameone"
v=$(cd "$repo/codenameone-python-runtime" && ls -d */ | head -1 | tr -d /)
python3 scripts/python-bench/run_bench.py \
--java-home "$JAVA_HOME" \
--runtime-jar "$repo/codenameone-python-runtime/$v/codenameone-python-runtime-$v.jar" \
--core-jar "$repo/codenameone-core/$v/codenameone-core-$v.jar" \
--transpiler-cp "$repo/codenameone-python-transpiler/$v/codenameone-python-transpiler-$v.jar" \
--json python-bench.json --check | tee -a "$GITHUB_STEP_SUMMARY"

- name: Upload the report
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: python-bench-report
path: python-bench.json

parparvm:
name: parparvm
needs: framework
runs-on: ubuntu-24.04
timeout-minutes: 60
env:
PYBENCH_M2: ${{ github.workspace }}/m2
steps:
- uses: actions/checkout@v4

- name: Install clang
run: |
bash scripts/ci/apt-get-update.sh
sudo apt-get install -y clang time

# The translator runs on JDK 8, the generated Java compiles on JDK 17.
- name: Set up JDK 8
uses: actions/setup-java@v4
with:
distribution: zulu
java-version: '8'

- name: Remember JDK 8
run: echo "JDK_8_HOME=$JAVA_HOME" >> "$GITHUB_ENV"

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17

- name: Remember JDK 17
run: echo "JAVA17_HOME=$JAVA_HOME" >> "$GITHUB_ENV"

- name: Set up CPython
uses: actions/setup-python@v5
with:
python-version: ${{ env.CPYTHON_VERSION }}

- name: Download the framework
uses: actions/download-artifact@v4
with:
name: python-bench-framework

- name: Unpack the framework
run: tar -xzf framework-m2.tgz

- name: Conformance, natively
run: scripts/python-bench/conformance_parparvm.sh

- name: Measure and gate
run: |
python3 scripts/python-bench/parparvm_table.py --json python-bench-parparvm.json --check \
| tee -a "$GITHUB_STEP_SUMMARY"

- name: Upload the report
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: python-bench-parparvm-report
path: python-bench-parparvm.json
Loading
Loading