Skip to content

Support Java 25 runtime compatibility#424

Open
robertpatrick wants to merge 1 commit into
jython:masterfrom
robertpatrick:gh-413-jdk25-compat
Open

Support Java 25 runtime compatibility#424
robertpatrick wants to merge 1 commit into
jython:masterfrom
robertpatrick:gh-413-jdk25-compat

Conversation

@robertpatrick

@robertpatrick robertpatrick commented May 9, 2026

Copy link
Copy Markdown

Fixes #413

Summary

This PR updates Jython for runtime compatibility with JDK 25 while keeping the release built with the lowest supported JDK target. The release artifacts were built with JDK 8 and then tested on JDK 8, 11, 17, 21, and 25 from the same build output. No multi-release JAR was needed.

This builds on the already-merged jffi update from #409 and incorporates/adapts fixes from:

Changes

  • Add JDK 25 runtime launcher support:
    • --enable-native-access=ALL-UNNAMED
    • --sun-misc-unsafe-memory-access=allow
  • Add JDK 9+ launcher/module opens needed by current runtime dependencies:
    • java.base/java.io
    • java.base/sun.nio.ch
  • Add matching manifest attributes to runtime/test jars:
    • Enable-Native-Access: ALL-UNNAMED
    • Add-Opens: java.base/java.io java.base/sun.nio.ch
  • Update ASM from 9.7 to 9.9.1.
  • Add jython.test.java.opts so CI/test runs can pass Java proxy/system properties without editing build files.
  • Added a jython.test.socket.unreachableHost system property to override the test_socket unreachable-host timeout target while preserving the existing 192.0.2.42 default.
  • Added new test-built Ant target that runs the tests without calling developer-build
  • Adjust version-sensitive tests for behavior changes in newer JDKs.
  • Skip SecurityManager and class-unloading leak tests where they are no longer valid on JDK 25.
  • Improve proxy-aware network tests while preserving direct localhost behavior.
  • Make modjy test failures propagate as process failures.
  • Suppress test-only noisy Netty logging from deliberate httplib socket error paths.
  • Release any partially consumed Netty socket buffer held in incoming_head during socket close.
  • Make test_mailbox.test_clean robust against stale deterministic tmp/foo and tmp/bar files.
  • Copy profile.properties into dist/javalib and adjust the bundled JIP profiler properties so the Java 8/11 --profile launcher tests produce output without noisy agent stack traces.
  • On Java 13+, report --profile as unsupported because the bundled Java Interactive Profiler agent is not compatible with modern class verification.

Proxy-sensitive network tests

When an external HTTP proxy is configured, this PR skips only the network cases that cannot work through an HTTP proxy:

  • test_urllib2net external FTP test is skipped when an external HTTP proxy is configured because it requires direct FTP access. Neither FTP-over-HTTP-proxy support nor Java FTP proxy property support is implemented in this PR.
  • test_ssl_jy raw external SSL socket tests are skipped because they open raw sockets and cannot use HTTP CONNECT.
  • test_smtpnet raw external SMTP SSL tests are skipped because they require direct SMTP-over-SSL socket access.

Higher-level external HTTPS tests were adjusted to use CONNECT where appropriate. Localhost/direct tests continue to run directly.

The relevant generic configuration surfaces for proxied test environments are:

  • Environment variables: http_proxy, https_proxy, no_proxy.
  • Java system properties passed through jython.test.java.opts system property:
    • http.proxyHost
    • http.proxyPort
    • http.nonProxyHosts
    • https.proxyHost
    • https.proxyPort
    • https.nonProxyHosts.

Validation

Release artifacts were built with JDK 8 using ant clean full-build:

  • dist/jython.jar
  • dist/jython-standalone.jar
  • dist/jython-installer.jar

The resulting artifacts still target JDK 8 bytecode/release metadata.

The regression matrix was run with:

  • JDK 8: ant test
  • JDK 11: ant test-built
  • JDK 17: ant test-built
  • JDK 21: ant test-built
  • JDK 25: ant test-built

Results:

  • JDK 8: 388 tests OK, 2 tests skipped; modjy OK (104 tests); BUILD SUCCESSFUL.
  • JDK 11: 388 tests OK, 2 tests skipped; modjy OK (104 tests); BUILD SUCCESSFUL.
  • JDK 17: 388 tests OK, 2 tests skipped; modjy OK (104 tests); BUILD SUCCESSFUL.
  • JDK 21: 388 tests OK, 2 tests skipped; modjy OK (104 tests); BUILD SUCCESSFUL.
  • JDK 25: 388 tests OK, 2 tests skipped; modjy OK (104 tests); BUILD SUCCESSFUL.

The two top-level skipped tests are existing resource-gated tests:

  • test_codecmaps_hk, requires urlfetch
  • test_curses, requires curses

They are not JDK 25 failures and are not proxy-related.

Additional focused checks used during development included JDK 25 command-line behavior, float behavior, imports, Java integration, subprocess/threading behavior, HTTP/URL handling, warning suppression, test_mailbox cleanup, and JDK 21/JDK 25 socket/SSL behavior.

@ohumbel

ohumbel commented May 10, 2026

Copy link
Copy Markdown
Contributor

This sounds promising!

On which platform, and with which exact command did you run the regression tests?
I'd like to reproduce them.

@robertpatrick

robertpatrick commented May 10, 2026

Copy link
Copy Markdown
Author

I ran this on my Mac laptop. Are there additional tests other than the CI tests Codex ran? Happy to run those if you point me in the right direction...

ant init regrtest-unix-ci

@robertpatrick robertpatrick force-pushed the gh-413-jdk25-compat branch from 777dcbc to 4e8bac7 Compare May 11, 2026 02:24
@robertpatrick

Copy link
Copy Markdown
Author

@ohumbel I expanded the scope of the PR. I ran the following commands:

  • JDK8: ant clean full-build and ant test
  • JDK11: ant test-built
  • JDK17: ant test-built
  • JDK21: ant test-built
  • JDK25: ant test-built

Let me know if there is anything else I can do to help.

@ohumbel

ohumbel commented May 11, 2026

Copy link
Copy Markdown
Contributor

@ohumbel I expanded the scope of the PR. I ran the following commands:

* JDK8: `ant clean full-build` and `ant test`

@robertpatrick When running ant test, I get:

launchertest-built:
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.3PA6YJJSWP/directory with spaces/bin/jython' -J-version
     [exec] ++ egrep -c '^java version '
     [exec] + '[' 0 == 1 ']'

BUILD FAILED
/Users/oti/stuff/gitrepo/robertpatrick/jython/build.xml:1493: exec returned: 1

Total time: 1 minute 15 seconds

The same error both on Mac and Ubuntu, using Java 8:

java -version 
openjdk version "1.8.0_492"
OpenJDK Runtime Environment (Temurin)(build 1.8.0_492-b09)
OpenJDK 64-Bit Server VM (Temurin)(build 25.492-b09, mixed mode)

@robertpatrick robertpatrick force-pushed the gh-413-jdk25-compat branch from 4e8bac7 to a4d3939 Compare May 11, 2026 13:16
@robertpatrick

Copy link
Copy Markdown
Author

@ohumbel Sorry, I don't use Open JDK. PR updated, please try again.

@jeff5

jeff5 commented May 12, 2026

Copy link
Copy Markdown
Member

@robertpatrick This all looks relevant and helpful. Thanks for tracking down so many apparent version-dependent changes. The additions to build.xml so that we can run a built copy are helpful too.

I know you've contributed before, but I can't trace a record of signing the CLA. It may be just that when you did, it wasn't correlated with a GitHub id. Or it may be we weren't all that strict.

This is really too many things in one PR. To help us know which changes are related, as reviewers or when someone does the archaeology later to understand a change they find problematic, could we divide this up please? Two of them @wfouche has cooking as PRs for anyway, as you identify, so if we can bank those we need not include them here.

@ohumbel

ohumbel commented May 12, 2026

Copy link
Copy Markdown
Contributor

@ohumbel Sorry, I don't use Open JDK. PR updated, please try again.

@robertpatrick If you have a look at ant-regrtest.yml, you can see that the pipelines also use the Eclipse Temurin distributions. That's the reason I test with those.

I have a positive and negative feedback for you.
On the positive side, I can reproduce your test results if I comment out launchertest.
On macOS Tahoe 26.4.1 (Intel), with the following java versions:

sdk use java 8.0.492-tem
sdk use java 11.0.31-tem
sdk use java 17.0.19-tem
sdk use java 21.0.11-tem
sdk use java 25.0.3-tem

I consistently get

     [exec] 388 tests OK.
     [exec] 2 tests skipped:
     [exec]     test_codecmaps_hk test_curses

Thats a good sign for me.
I need some more time to do the same runs on Ubuntu, and possibly on Windows.

launchertest gets a bit further (sdk use java 8.0.492-tem), but fails as follows:

launchertest-built:
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces/bin/jython' -J-version
     [exec] ++ egrep -c '^(java|openjdk) version '
     [exec] + '[' 1 == 1 ']'
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces/bin/jython' --version
     [exec] ++ egrep -c '^Jython '
     [exec] + '[' 1 == 1 ']'
     [exec] + JYTHON_OPTS=--version
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces/bin/jython'
     [exec] ++ egrep -c '^Jython '
     [exec] + '[' 1 == 1 ']'
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces/bin/jython' --help
     [exec] ++ egrep -c '^usage: '
     [exec] + '[' 1 == 1 ']'
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces/bin/jython' --help
     [exec] ++ egrep -c '^Jython launcher options:'
     [exec] + '[' 1 == 1 ']'
     [exec] + set +e
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces/bin/jython' -c 'import sys; sys.exit(5)'
     [exec] + '[' 5 == 5 ']'
     [exec] + set -e
     [exec] ++ '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces/bin/jython' -c 'import sys; print sys.executable is not None,'
     [exec] + '[' True == True ']'
     [exec] ++ java_major_version '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces/bin/jython'
     [exec] ++ local output version major
     [exec] +++ '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces/bin/jython' -J-version
     [exec] ++ output='openjdk version "1.8.0_492"
     [exec] OpenJDK Runtime Environment (Temurin)(build 1.8.0_492-b09)
     [exec] OpenJDK 64-Bit Server VM (Temurin)(build 25.492-b09, mixed mode)'
     [exec] +++ expr 'openjdk version "1.8.0_492"
     [exec] OpenJDK Runtime Environment (Temurin)(build 1.8.0_492-b09)
     [exec] OpenJDK 64-Bit Server VM (Temurin)(build 25.492-b09, mixed mode)' : '.*version "\([^"]*\)"'
     [exec] ++ version=1.8.0_492
     [exec] ++ case "$version" in
     [exec] ++ major=8.0_492
     [exec] ++ major=8
     [exec] ++ echo 8
     [exec] + JAVA_MAJOR=8
     [exec] + JDB_OUTPUT=/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/jdb.out
     [exec] + set +e
     [exec] + echo run
     [exec] + sleep 3
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces/bin/jython' --jdb -c 'print '\''\ntest'\'''
     [exec] + JDB_STATUS=0
     [exec] + set -e
     [exec] ++ egrep -c '^test' /var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/jdb.out
     [exec] + '[' 0 == 1 ']'
     [exec] + cat /var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/jdb.out
     [exec] Initializing jdb ...
     [exec] > run org.python.util.jython -c "print '\ntest'"
     [exec] VM start exception: VM initialization failed for: /Users/oti/.sdkman/candidates/java/8.0.492-tem/jre/bin/java -Xmx512m -Xss2560k -Dfile.encoding=UTF-8 -classpath /var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces/jython-dev.jar:/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces/jython-test.jar:/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces/javalib/*: -Dpython.home=/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces -Dpython.executable=/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.zuy6atO8ey/directory with spaces/bin/jython -Xdebug -Xrunjdwp:transport=dt_socket,address=rope.local:57105,suspend=y org.python.util.jython -c print '\ntest'
     [exec] 
     [exec] Error: Could not find or load main class with
     [exec] 
     [exec] Fatal error:
     [exec] Target VM failed to initialize.
     [exec] + '[' 0 -ne 0 ']'
     [exec] + exit 1

BUILD FAILED
/Users/oti/stuff/gitrepo/robertpatrick/jython/build.xml:1493: exec returned: 1

Total time: 1 minute 23 seconds

@robertpatrick

Copy link
Copy Markdown
Author

@jeff5

I know you've contributed before, but I can't trace a record of signing the CLA. It may be just that when you did, it wasn't correlated with a GitHub id. Or it may be we weren't all that strict.

Done

This is really too many things in one PR.

Well... It is hard to know if a PR is useful if you cannot actually build and test it with the stated goal.

To help us know which changes are related, as reviewers or when someone does the archaeology later to understand a change they find problematic, could we divide this up please?

And how exactly would you suggest we do that? Send a bunch of related PRs, none of which actually achieve the stated goal? How exactly do you vet those PRs individually?

Two of them @wfouche has cooking as PRs for anyway, as you identify, so if we can bank those we need not include them here.

Again, I need Jython support for JDK 25 and so I achieved this and met all of the goals that have been stated. I did give credit to those two PRs but if they were ready, why haven't you merged them already? I seem to recall that you had some feedback on one of them that they did not achieve the objective the way that you wanted.

@robertpatrick robertpatrick force-pushed the gh-413-jdk25-compat branch from a4d3939 to 43bc8e8 Compare May 12, 2026 13:06
@robertpatrick

Copy link
Copy Markdown
Author

@ohumbel Updated the PR to address the issue with the launchertest-built target.

I consistently get

 [exec] 388 tests OK.
 [exec] 2 tests skipped:
 [exec]     test_codecmaps_hk test_curses

Those two skips are from the existing Ant/regrtest resource configuration, not from this PR.

Both ant test and the upstream regrtest-ci target run regrtest with:

    --use network,subprocess

They do not enable urlfetch or curses.

  • test_codecmaps_hk requires urlfetch because it downloads an external codec mapping file. We can run that as an additional optional validation where outbound HTTP is available, but I would not make the main JDK compatibility matrix depend on a third-party URL.

  • test_curses requires the curses resource and then imports the native _curses module. Jython does not ship a _curses implementation, and installing system ncurses/libcurses does not make CPython’s native extension available to Jython. Making that test run would be a separate Jython curses-support feature, not a JDK 25 compatibility issue.

I am happy to go do more work to make sure that all of your requirements for OS and JDK versions are met. However, I think you and @jeff5 need to decide what you want to do. I do not want to waste time.

We need a working version of Jython that runs properly on JDK25, and we need it soon. I tried to help the process along with this PR but apparently, didn't do it the way @jeff5 wanted. So, what is the plan for getting JDK 25 support added in the near future if it is not this PR?

Note that I can continue my work on this PR to verify OS/JDK support. However, if you two decide not to merge it after I satisfy the OS/JDK requirements, we will be forced to fork Jython, apply the PR, and move forward. As one of the largest consumers of Jython, that would be bad for Jython as a whole, and create extra work for us but we have dates to meet.

@ohumbel

ohumbel commented May 12, 2026

Copy link
Copy Markdown
Contributor

@robertpatrick
The 2 skips are expected and completely ok, I think.

Being "only" a contributor like you, I just wanted to help verify the PR locally - time is always short on all sides.
My plans are to help moving Jython forward, towards modern Java and up to date external libraries.

@ohumbel

ohumbel commented May 12, 2026

Copy link
Copy Markdown
Contributor

@robertpatrick
launchertest seems to be a hard nut to crack. I ran this target only: ant launchertest:

launchertest-built:
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.iA57H96DUy/directory with spaces/bin/jython' -J-version
     [exec] ++ egrep -c '^(java|openjdk) version '
     [exec] + '[' 1 == 1 ']'
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.iA57H96DUy/directory with spaces/bin/jython' --version
     [exec] ++ egrep -c '^Jython '
     [exec] + '[' 1 == 1 ']'
     [exec] + JYTHON_OPTS=--version
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.iA57H96DUy/directory with spaces/bin/jython'
     [exec] ++ egrep -c '^Jython '
     [exec] + '[' 1 == 1 ']'
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.iA57H96DUy/directory with spaces/bin/jython' --help
     [exec] ++ egrep -c '^usage: '
     [exec] + '[' 1 == 1 ']'
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.iA57H96DUy/directory with spaces/bin/jython' --help
     [exec] ++ egrep -c '^Jython launcher options:'
     [exec] + '[' 1 == 1 ']'
     [exec] + set +e
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.iA57H96DUy/directory with spaces/bin/jython' -c 'import sys; sys.exit(5)'
     [exec] + '[' 5 == 5 ']'
     [exec] + set -e
     [exec] ++ '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.iA57H96DUy/directory with spaces/bin/jython' -c 'import sys; print sys.executable is not None,'
     [exec] + '[' True == True ']'
     [exec] ++ java_major_version '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.iA57H96DUy/directory with spaces/bin/jython'
     [exec] ++ local output version major
     [exec] +++ '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.iA57H96DUy/directory with spaces/bin/jython' -J-version
     [exec] ++ output='openjdk version "1.8.0_492"
     [exec] OpenJDK Runtime Environment (Temurin)(build 1.8.0_492-b09)
     [exec] OpenJDK 64-Bit Server VM (Temurin)(build 25.492-b09, mixed mode)'
     [exec] +++ expr 'openjdk version "1.8.0_492"
     [exec] OpenJDK Runtime Environment (Temurin)(build 1.8.0_492-b09)
     [exec] OpenJDK 64-Bit Server VM (Temurin)(build 25.492-b09, mixed mode)' : '.*version "\([^"]*\)"'
     [exec] ++ version=1.8.0_492
     [exec] ++ case "$version" in
     [exec] ++ major=8.0_492
     [exec] ++ major=8
     [exec] ++ echo 8
     [exec] + JAVA_MAJOR=8
     [exec] + JDB_OUTPUT=/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.iA57H96DUy/jdb.out
     [exec] + set +e
     [exec] + echo run
     [exec] + sleep 3
     [exec] + '/var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.iA57H96DUy/directory with spaces/bin/jython' --jdb -c 'print '\''\ntest'\'''
     [exec] + JDB_STATUS=0
     [exec] + set -e
     [exec] ++ egrep -c '^test' /var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.iA57H96DUy/jdb.out
     [exec] + '[' 0 == 1 ']'
     [exec] + cat /var/folders/g9/t4tbc7x57jn74ch4g1978c3w0000gn/T/test-jython.XXXXXX.iA57H96DUy/jdb.out
     [exec] Initializing jdb ...
     [exec] > run org.python.util.jython -c "print '\ntest'"
     [exec] Set uncaught java.lang.Throwable
     [exec] Set deferred uncaught java.lang.Throwable
     [exec] > 
     [exec] VM Started: Input stream closed.
     [exec] + '[' 0 -ne 0 ']'
     [exec] + exit 1

BUILD FAILED
/Users/oti/stuff/gitrepo/robertpatrick/jython/build.xml:1493: exec returned: 1

Total time: 17 seconds

@Stewori

Stewori commented May 12, 2026

Copy link
Copy Markdown
Member

However, if you two decide not to merge it after I satisfy the OS/JDK requirements, we will be forced to fork Jython, apply the PR, and move forward. As one of the largest consumers of Jython, that would be bad for Jython as a whole, and create extra work for us but we have dates to meet.

Please, let's remind ourselves that everyone is working on this voluntarily. No need for "threats" like this - I really see no way how Jython 2.7.5 could be released without including this PR the one or other way. So, no worries - it will surely be accepted once remaining issues are solved.

That said, if we merge @wfouche 's PRs first, the diff should just adopt and we can merge this PR on top, I suppose. (Perhaps it will require resolving a mild merge conflict if at all.)

@robertpatrick

Copy link
Copy Markdown
Author

@ohumbel I will go download and install these non-standard JDK distributions and try to resolve the issue.

@jeff5

jeff5 commented May 12, 2026

Copy link
Copy Markdown
Member

CLA: thank-you.

... could we divide this up please?

And how exactly would you suggest we do that? Send a bunch of related PRs, none of which actually achieve the stated goal? How exactly do you vet those PRs individually?

I think the obvious approach is to address test failures (in regrtest with various -u settings), in groups that have a common cause. #407 and #410 achieve isolated advances that can be reviewed, and tweaks proposed, although #413 overlooks what may be left to do.

@robertpatrick

Copy link
Copy Markdown
Author

@jeff5 I have no time or interest in dividing this up.

Just so we are clear, I am doing this work because my employer needs these changes and we want to be good open-source citizens. I was not trying to make threats earlier, I was stating the facts that we have to ship this and have dates that we need to meet.

I will continue to focus on testing and resolving issues in their non-standard JDKs and Linux/Windows. If you want to break it up, into separate PRs, be my guest. For me, this is not about credit, my ego, or any such thing. It is about getting the changes made as soon as possible to meet the dates my employer has.

@robertpatrick

robertpatrick commented May 13, 2026

Copy link
Copy Markdown
Author

@ohumbel I cannot reproduce your issue using the same Eclipse Temurin JDK 1.8.0_492 on macOS Tahoe 26.4.1. Same result without the -D overrides for the JDBC jars.

rpatrick@rpatrick-mac1 jython % java -version
openjdk version "1.8.0_492"
OpenJDK Runtime Environment (Temurin)(build 1.8.0_492-b09)
OpenJDK 64-Bit Server VM (Temurin)(build 25.492-b09, mixed mode)
rpatrick@rpatrick-mac1 jython %  ant launchertest \
    -Dinformix.jar=/tmp/jdbc-4.10.12.jar \
    -Doracle.jar=/opt/weblogic/soa12214/oracle_common/modules/oracle.jdbc/ojdbc8.jar
Buildfile: /Users/rpatrick/Projects/jython/build.xml

developer-preinit:

common-dirs:

common-jars:

common-paths:

common-constants:

common-config:

common-version-strings:

init:

antlr-up-to-date:

antlr-gen:

git-present:

git-is-tagged:

git-is-unmodified:

brand-up-to-date:

brand-version-metadata:

brand-version-nogit:

brand-version:
     [echo] Writing git and build metadata to version.properties.
     [echo] jython.version        = 2.7.5a1-DEV
     [echo] build.git.branch      = remotes/origin/gh-413-jdk25-compat
     [echo] build.git.version     = 43bc8e8bb
     [echo] build.git.tag         = heads/gh-413-jdk25-compat

compile:

expose:

jar:
      [jar] Updating jar: /Users/rpatrick/Projects/jython/dist/jython-dev.jar

compile-test:

jar-test:
      [jar] Updating jar: /Users/rpatrick/Projects/jython/dist/jython-test.jar

copy-javalib:

copy-bin:

copy-cpythonlib:

copy-lib:

copy-dev:

pycompile:

developer-build:

launchertest-built:
     [exec] + '/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/bin/jython' -J-version
     [exec] ++ egrep -c '^(java|openjdk) version '
     [exec] + '[' 1 == 1 ']'
     [exec] + '/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/bin/jython' --version
     [exec] ++ egrep -c '^Jython '
     [exec] + '[' 1 == 1 ']'
     [exec] + JYTHON_OPTS=--version
     [exec] + '/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/bin/jython'
     [exec] ++ egrep -c '^Jython '
     [exec] + '[' 1 == 1 ']'
     [exec] + '/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/bin/jython' --help
     [exec] ++ egrep -c '^usage: '
     [exec] + '[' 1 == 1 ']'
     [exec] + '/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/bin/jython' --help
     [exec] ++ egrep -c '^Jython launcher options:'
     [exec] + '[' 1 == 1 ']'
     [exec] + set +e
     [exec] + '/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/bin/jython' -c 'import sys; sys.exit(5)'
     [exec] + '[' 5 == 5 ']'
     [exec] + set -e
     [exec] ++ '/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/bin/jython' -c 'import sys; print sys.executable is not None,'
     [exec] + '[' True == True ']'
     [exec] ++ java_major_version '/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/bin/jython'
     [exec] ++ local output version major
     [exec] +++ '/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/bin/jython' -J-version
     [exec] ++ output='openjdk version "1.8.0_492"
     [exec] OpenJDK Runtime Environment (Temurin)(build 1.8.0_492-b09)
     [exec] OpenJDK 64-Bit Server VM (Temurin)(build 25.492-b09, mixed mode)'
     [exec] +++ expr 'openjdk version "1.8.0_492"
     [exec] OpenJDK Runtime Environment (Temurin)(build 1.8.0_492-b09)
     [exec] OpenJDK 64-Bit Server VM (Temurin)(build 25.492-b09, mixed mode)' : '.*version "\([^"]*\)"'
     [exec] ++ version=1.8.0_492
     [exec] ++ case "$version" in
     [exec] ++ major=8.0_492
     [exec] ++ major=8
     [exec] ++ echo 8
     [exec] + JAVA_MAJOR=8
     [exec] + JDB_OUTPUT=/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/jdb.out
     [exec] + set +e
     [exec] + echo run
     [exec] + sleep 3
     [exec] + '/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/bin/jython' --jdb -c 'print '\''\ntest'\'''
     [exec] + JDB_STATUS=0
     [exec] + set -e
     [exec] ++ egrep -c '^test' /var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/jdb.out
     [exec] + '[' 1 == 1 ']'
     [exec] + :
     [exec] + '[' 8 -lt 13 ']'
     [exec] + '/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/bin/jython' --profile -c pass
     [exec] ++ egrep -c '^\| Most expensive methods'
     [exec] + '[' 2 -ge 1 ']'
     [exec] + '[' -f profile.txt ']'
     [exec] + rm profile.txt
     [exec] + CLASSPATH='/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/Lib/test/blob.jar'
     [exec] + '/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/bin/jython' -c 'print __import__('\''Blob'\'')'
     [exec] ++ egrep -c Blob
     [exec] + '[' 1 == 1 ']'
     [exec] + '[' 8 -lt 13 ']'
     [exec] + CLASSPATH='/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/Lib/test/blob.jar'
     [exec] + '/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/directory with spaces/bin/jython' --profile -c 'print __import__('\''Blob'\'')'
     [exec] ++ egrep -c Blob
     [exec] Using the generic class loader filter.
     [exec] Java Interactive Profiler: starting
     [exec] Controller -- shuttingdown
     [exec] + '[' 1 == 1 ']'
     [exec] + set +ex
     [exec] + /Users/rpatrick/Projects/jython/dist/bin/jython -J-version
     [exec] ++ egrep -c '^(java|openjdk) version '
     [exec] + '[' 1 == 1 ']'
     [exec] + /Users/rpatrick/Projects/jython/dist/bin/jython --version
     [exec] ++ egrep -c '^Jython '
     [exec] + '[' 1 == 1 ']'
     [exec] + JYTHON_OPTS=--version
     [exec] + /Users/rpatrick/Projects/jython/dist/bin/jython
     [exec] ++ egrep -c '^Jython '
     [exec] + '[' 1 == 1 ']'
     [exec] + /Users/rpatrick/Projects/jython/dist/bin/jython --help
     [exec] ++ egrep -c '^usage: '
     [exec] + '[' 1 == 1 ']'
     [exec] + /Users/rpatrick/Projects/jython/dist/bin/jython --help
     [exec] ++ egrep -c '^Jython launcher options:'
     [exec] + '[' 1 == 1 ']'
     [exec] + set +e
     [exec] + /Users/rpatrick/Projects/jython/dist/bin/jython -c 'import sys; sys.exit(5)'
     [exec] + '[' 5 == 5 ']'
     [exec] + set -e
     [exec] ++ /Users/rpatrick/Projects/jython/dist/bin/jython -c 'import sys; print sys.executable is not None,'
     [exec] + '[' True == True ']'
     [exec] ++ java_major_version /Users/rpatrick/Projects/jython/dist/bin/jython
     [exec] ++ local output version major
     [exec] +++ /Users/rpatrick/Projects/jython/dist/bin/jython -J-version
     [exec] ++ output='openjdk version "1.8.0_492"
     [exec] OpenJDK Runtime Environment (Temurin)(build 1.8.0_492-b09)
     [exec] OpenJDK 64-Bit Server VM (Temurin)(build 25.492-b09, mixed mode)'
     [exec] +++ expr 'openjdk version "1.8.0_492"
     [exec] OpenJDK Runtime Environment (Temurin)(build 1.8.0_492-b09)
     [exec] OpenJDK 64-Bit Server VM (Temurin)(build 25.492-b09, mixed mode)' : '.*version "\([^"]*\)"'
     [exec] ++ version=1.8.0_492
     [exec] ++ case "$version" in
     [exec] ++ major=8.0_492
     [exec] ++ major=8
     [exec] ++ echo 8
     [exec] + JAVA_MAJOR=8
     [exec] + JDB_OUTPUT=/var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/jdb.out
     [exec] + set +e
     [exec] + echo run
     [exec] + sleep 3
     [exec] + /Users/rpatrick/Projects/jython/dist/bin/jython --jdb -c 'print '\''\ntest'\'''
     [exec] + JDB_STATUS=0
     [exec] + set -e
     [exec] ++ egrep -c '^test' /var/folders/lq/3_tv3hpd3yv2f7r2hf4yzbfc0000gp/T/test-jython.XXXXXX.MdK0j8mmXi/jdb.out
     [exec] + '[' 1 == 1 ']'
     [exec] + :
     [exec] + '[' 8 -lt 13 ']'
     [exec] + /Users/rpatrick/Projects/jython/dist/bin/jython --profile -c pass
     [exec] ++ egrep -c '^\| Most expensive methods'
     [exec] + '[' 2 -ge 1 ']'
     [exec] + '[' -f profile.txt ']'
     [exec] + rm profile.txt
     [exec] + CLASSPATH=/Users/rpatrick/Projects/jython/dist/Lib/test/blob.jar
     [exec] + /Users/rpatrick/Projects/jython/dist/bin/jython -c 'print __import__('\''Blob'\'')'
     [exec] ++ egrep -c Blob
     [exec] + '[' 1 == 1 ']'
     [exec] + '[' 8 -lt 13 ']'
     [exec] + CLASSPATH=/Users/rpatrick/Projects/jython/dist/Lib/test/blob.jar
     [exec] + /Users/rpatrick/Projects/jython/dist/bin/jython --profile -c 'print __import__('\''Blob'\'')'
     [exec] ++ egrep -c Blob
     [exec] Using the generic class loader filter.
     [exec] Java Interactive Profiler: starting
     [exec] Controller -- shuttingdown
     [exec] + '[' 1 == 1 ']'
     [exec] + set +ex
     [exec] Test successful.

launchertest:

BUILD SUCCESSFUL
Total time: 43 seconds
rpatrick@rpatrick-mac1 jython % 

@robertpatrick robertpatrick force-pushed the gh-413-jdk25-compat branch from 43bc8e8 to 0ba1cae Compare May 13, 2026 02:32
@robertpatrick

robertpatrick commented May 13, 2026

Copy link
Copy Markdown
Author

Tested on Oracle Linux 9.6. The only update that was required was adding a system property that allowed me to override the test_socket.py file's default, hard-coded unreachable host 192.0.2.42--which was reachable on our network.

The test matrix run was:

  • Eclipse Temurin JDK 8u492: PASS, 388 tests OK, 2 skipped, modjy OK (104 tests)
  • Eclipse Temurin JDK 11.0.31: PASS, 388 tests OK, 2 skipped, modjy OK (104 tests)
  • Eclipse Temurin JDK 17.0.19: PASS, 388 tests OK, 2 skipped, modjy OK (104 tests)
  • Eclipse Temurin JDK 21.0.11: PASS, 388 tests OK, 2 skipped, modjy OK (104 tests)
  • Eclipse Temurin JDK 25.0.3: PASS, 388 tests OK, 2 skipped, modjy OK (104 tests)

I will go test on Windows next.

Comment thread Lib/test/test_httplib.py
Comment thread Lib/test/test_socket.py
Comment thread Lib/test/test_urllib2.py Outdated
Comment thread Lib/test/test_urllibnet.py
Comment thread Lib/test/test_urllibnet.py
Comment thread Lib/test/test_urllibnet.py
Comment thread src/org/python/core/PySystemState.java

if (exception != null) {
logger.log(Level.WARNING, "Unable to format console messages: {0}",
logger.log(Level.FINE, "Unable to format console messages: {0}",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this relevant for a potential doctest failure? Or is it just silencing some noise?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just silencing noise

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that in normal circumstances, a user or application manager might want to know that they aren't going to get properly formatted log messages. ISTR it emerges as "noise" in a test involvig a security manager, but I've never found it objectionable.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been pondering this noise-silencing decision, too. IMHO noise silencing is not necessarily a bad thing. Ideally, the warning would pop up only in verbose mode. Would Level.FINE achieve this? Since this tiny detail has not the urgency of Java 25 compatibility, I would ideally like to see the discussion decoupled and in a separate issue. However, I'm personally fine with keeping the change for now as-is. We can open a separate issue for this and assess if it can be made somehow verbose-mode only and adjust it in a new PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Supporting Java 25 does not motivate a change from WARNING to FINE. By all means take the discussion elsewhere. I have learned not to change behaviour without a positive reason.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jeff5 Well...the fact is that this logger serves two purposes so Codex was simply trying to clean up unnecessary noise in the test. We could either split these two purposes so that each logs a distinct message at the right level or just restore it to WARNING. At the end of the day, I could care less what we do here.

However, let's not pretend that there isn't technical debt in the code...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good observation on this bit of code, but has nothing to do with Java 25. I am content with this noise.

Comment thread src/shell/jython Outdated
Comment thread src/shell/jython.py
Comment thread NEWS
@ohumbel

ohumbel commented May 13, 2026

Copy link
Copy Markdown
Contributor

@robertpatrick Then I am sorry to suffer under the "it's not working on my machine" syndrome.

The pipelines decide.

Therefore I won't bother you with failing Ubuntu and Windows, both behind corporate firewall and proxy.

@robertpatrick

Copy link
Copy Markdown
Author

@robertpatrick Then I am sorry to suffer under the "it's not working on my machine" syndrome.

The pipelines decide.

Therefore I won't bother you with failing Ubuntu and Windows, both behind corporate firewall and proxy.

No worries, I am also behind a corporate firewall and proxy. I was able to get it to pass in that environment by exporting the JAVA_OPTS environment variable with the necessary proxy -Ds.

@robertpatrick robertpatrick force-pushed the gh-413-jdk25-compat branch 2 times, most recently from 7887892 to 9af02e1 Compare May 13, 2026 13:21
@Stewori

Stewori commented May 13, 2026

Copy link
Copy Markdown
Member

For the record, as always, when binary files occur in a PR I routinely verify their authenticity. I hereby confirm that the provided binary files in this PR asm-9.9.1.jar, asm-util-9.9.1.jar and asm-commons-9.9.1.jar are binary identical to those provided on maven central.

@robertpatrick Thanks for addressing all of my remarks thoroughly!

@jeff5 jeff5 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robertpatrick A lot of relly good stuff here as commented earlier.

The changes made to permit testing in a proxied environment are a worthy objective in their own right, independent of the Java 25 compatibility. They're not things I know how to test but you're obviously a sophisticated user. (We'll credit you not Codex.)

The only blocker I think is that the PR must not modify lib-python. An alternative exists.

Other comments are either appreciative or a question.

Comment thread lib-python/2.7/test/test_mailbox.py
Comment thread lib-python/2.7/test/test_smtpnet.py
Comment thread lib-python/2.7/httplib.py
Comment thread Lib/test/test_float_jy.py

if (exception != null) {
logger.log(Level.WARNING, "Unable to format console messages: {0}",
logger.log(Level.FINE, "Unable to format console messages: {0}",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that in normal circumstances, a user or application manager might want to know that they aren't going to get properly formatted log messages. ISTR it emerges as "noise" in a test involvig a security manager, but I've never found it objectionable.

Comment thread build.gradle
Comment thread src/shell/jython.py
Comment thread src/shell/jython
@robertpatrick robertpatrick force-pushed the gh-413-jdk25-compat branch 2 times, most recently from 77419e5 to 6532e8e Compare May 14, 2026 17:29
@robertpatrick

Copy link
Copy Markdown
Author

@jeff5 @Stewori I just updated the commit with the changes made for Windows build and test (except for Issue #426) and moved changes out of lib-python/2.7, as requested. Since the PR is large, I will give you Codex's enumeration of the changes, which will hopefully make it easier to review:

  • build.xml
    • Added jython.launcher.test.java.opts, combining locale opts, caller-supplied jython.test.java.opts, JDK 9 module opens, and JDK 25 native-access/Unsafe opts.
    • Changed launcher-based test targets to pass that through JAVA_OPTS.
    • Added JAVA_OPTS to the Windows launcher invocations that previously did not pass it.
    • Kept the fix scoped to build/test execution, since the Windows native launcher issue Windows native launcher should auto-add JDK 9+/25 compatibility args #426 is now tracked separately.
  • Lib/test/test_jython_launcher.py
    • Uses a forward-slash synthetic Windows classpath path for --print parsing tests.
    • Added coverage for modern Java launcher options.
    • On Windows, verifies the native launcher forwards JAVA_OPTS.
    • On Unix-like launchers, verifies scripts synthesize JDK-version-specific args.
    • Fixed Windows detection so Git/MSYS/Cygwin uname on PATH does not make the test treat the native Windows launcher like a Unix script launcher.
  • Lib/test/test_support.py
    • Updated EnvironmentVarGuard bookkeeping for Windows case-insensitive environment variables.
    • It now canonicalizes only the internal saved-state key, while preserving the caller’s original spelling foractual os.environ operations.
    • This prevents http_proxy / HTTP_PROXY-style aliases from being restored and then accidentally deleted during cleanup.
  • Lib/test/test_os_jy.py
    • Added a Windows-only regression test for EnvironmentVarGuard.
    • The test verifies that unsetting both lowercase and uppercase spellings restores the original value correctly.
  • Lib/test/test_socket.py
    • Added UDP client socket cleanup in ThreadedUDPSocketTest.clientTearDown().
    • The comment documents the Windows/Netty hang seen in full regrtest runs, where delayed datagram channel cleanup could leave later threaded UDP tests blocked.
  • Lib/test/test_urllib2_localnet.py
    • Added as a Lib/test overlay copy instead of modifying lib-python/2.7/test.
    • Only intentional change from upstream is a tearDown() that resets the process-global urllib2 opener with urllib2.install_opener(None).
    • This prevents the localhost test’s proxy-disabled opener from leaking into later urllib2 network tests that need the real proxy environment.
  • tests/java/javatests/Issue2455Test.java
    • Changed the test to append the temporary directory directly to sys.path through PySystemState.
    • Avoids embedding a Windows path with backslashes into a Python string, where backslashes can be interpreted as escapes.
  • tests/java/org/python/indexer/TestBase.java
    • Switched source loading to Util.readFile(path) so raw line endings are preserved.
    • Adjusted the testGetSource() assertion to normalize CRLF only for that assertion.
    • This keeps indexer offsets consistent on Windows checkouts.
  • tests/modjy/build.xml
    • Added a default empty jython.test.java.opts.
    • Passes jython.test.java.opts into the forked modjy Java test process.
    • This lets matrix runs propagate shared proxy/socket JVM properties into modjy tests.

@robertpatrick robertpatrick force-pushed the gh-413-jdk25-compat branch from 6532e8e to dd3c22d Compare May 15, 2026 03:24
@robertpatrick

robertpatrick commented May 15, 2026

Copy link
Copy Markdown
Author

I just pushed what I hope to be the last cleanup changes to the PR. One of the things in this commit is trying to clean up race conditions between the socket tests, which were mostly relying on implicit closing of sockets bound to ports that are reused across mutliple tests, primarily in test_socket.py. Note that my Windows VM did not see these errors but my MBP M4 Pro did. I do not believe that this PR introduced these race conditions and I am hopeful we have cleaned at least some of them up. However, race conditions are difficult to detect so I honestly cannot say that the PR fixes every one of them.

@robertpatrick robertpatrick requested a review from jeff5 May 15, 2026 03:39
@ohumbel

ohumbel commented May 16, 2026

Copy link
Copy Markdown
Contributor

I configured a matrix to build with java 8 and then run the ci tests with java versions up to 25.
GitHub actions do not offer java 8 on every platform any more, therefore the test runs start with 11.
The test_socket* tests turned out to be quite flaky, so I excluded them.
The results can be found on this local pull request.

If there are changes to PR #424, I can manually trigger the pipelines again.

Update 2026-05-19: The link is now working

@robertpatrick

robertpatrick commented May 17, 2026

Copy link
Copy Markdown
Author

@robertpatrick A lot of relly good stuff here as commented earlier.

I think that in normal circumstances, a user or application manager might want to know that they aren't going to get properly formatted log messages. ISTR it emerges as "noise" in a test involvig a security manager, but I've never found it objectionable.

@jeff5 I think the problem is that this line is doing two different jobs at the moment. It reports both:

  • “we couldn’t set the preferred SimpleFormatter format”, and
  • “we couldn’t install/configure the org.python console handler”.

The first is mostly a formatting degradation and can be noisy under a security manager; the second is more operationally significant because -v logging may not behave as intended.

My suggestion is to split those cases instead of using one final message for both. I’d log the formatter-property failure at FINE or CONFIG, but keep a WARNING when we fail to attach/configure the console handler. That preserves the useful signal for users/application managers without making the security-manager test noise drive the level for both cases.

@jeff5

jeff5 commented May 19, 2026

Copy link
Copy Markdown
Member

I think that's a good analysis. Also, the change is not of the essence for Java 25.

@ohumbel

ohumbel commented May 19, 2026

Copy link
Copy Markdown
Contributor

I configured a matrix to build with java 8 and then run the ci tests with java versions up to 25. GitHub actions do not offer java 8 on every platform any more, therefore the test runs start with 11. The test_socket* tests turned out to be quite flaky, so I excluded them. The results can be found on this local pull request.

There was a typo in the link - sorry for that.
It is now correct: Cafino#1.

@jeff5 jeff5 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having studied this carefully, I now understand it in three main parts:

  1. Bringing JARs up to date.
  2. Compatibility with Java 25: mainly native access for Java 25, but includes test_float_jy.
  3. Changes to network support to permit testing behind a proxy.

These are all useful. There are other minor tweaks in the PR too, but I have commented where I think these are misconceived or unnecessary. I'm open to correction on those comments.

I would like to split the PR into those parts so that contributors coming after may more easily associate a change to its intent. They pretty much split by file, although build.xml has elements of them all.

As you've said @robertpatrick that you don't have the time for that reorganisation, I'll do it and aim to credit you in the commits. If some end up with my name on, it's my lack of git foo, not intentional.


if (exception != null) {
logger.log(Level.WARNING, "Unable to format console messages: {0}",
logger.log(Level.FINE, "Unable to format console messages: {0}",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good observation on this bit of code, but has nothing to do with Java 25. I am content with this noise.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you encounter a problem with line-endings? This test runs fine for me on Windows. The test material has LF line-endings and we use autocrlf=input.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jeff5 things are not as clear cut as relevant to JDK 25 or not. Many tests don’t clean up after themselves and create race conditions. Since the ONLY way to validate changes are the tests, I had no choice but to fix issues causing test failures. Since many of the test changes were addressing race conditions in the tests, by definition, slower machines may not observe these test failures while faster machines will. Do whatever you want but it is naive to think that just because you don’t observe an issue yourself that the issue doesn’t exist.

I spent many hours (and hundreds of millions of tokens) creating and testing the changes in the PR across Mac, Linux, and Windows. How many other contributors do this?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The particular comment is about whether this test encounters CRLF line endings, which it is hard to see as a concurrency, a processor speed or a clean-up issue. If you see such line endings in the files themselves, they were most likely added by git during checkout.

Taking your comment as general to the review, yes, some tests can be flakey, and none of them are designed to run concurrently: many use the same file name as a temporary for example. I also understand that you would want to make the test suite run in your proxied environment before working on the Java 25 specific fixes.

@robertpatrick robertpatrick May 29, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The race conditions have nothing to do with running tests concurrently. They are all about proper resource cleanup (e.g., ports, mailboxes, etc.) when one test completes so that the next test being run can reuse the same resource without encountering unexpected conditions (e.g., port already in use, mailbox already exists, etc.).

One common pattern I found was that the tests were relying on JVM garbage collection to clean up these external resources. That approach is not reliable and creates a race condition on whether or not GC clears the resource prior to the next test trying to use it.

Do you have an ETA when the changes will be merged?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One common pattern I found was that the tests were relying on JVM garbage collection to clean up these external resources. That approach is not reliable and creates a race condition on whether or not GC clears the resource prior to the next test trying to use it.

Yes, we've fixed tests ourselves that (rather) rely on CPython garbage collection, which is immediate, of course. Guidance says you shouldn't rely on that but authors are not reminded by failure.

It's reasonable to think I can get it ready to merge over the weekend.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test runs fine for me., but I see now that I have just been lucky with backslashes and Python 2 is tolerant about them.

So it's a bug found, but it has nothing to do with Java 25, so thank you Codex and I shall extract this one to a separate change set. I have a smaller fix anyway.

Is this Codex being an enthusiastic novice? Noticing unrelated bugs and being unable to resist the temptation to fix them.

Comment thread Lib/test/test_mailbox.py
Comment on lines +635 to +636
self._delete_recursively(foo_path)
self._delete_recursively(bar_path)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only these two lines are new. They don't exist in the latest upstream test. (Other improvements do.)

Again, this seems to be Codex making improvements unrelated to the objective. The original runs fine for me. Did you really have trouble? If not, I'd revert the shadowing file.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, more race conditions

Comment thread Lib/httplib.py
Comment on lines +1101 to +1103
try:
thelen = str(os.path.getsize(body.name))
except (AttributeError, OSError, TypeError):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 3 lines are the reason for creating a shadow copy of the file. But why are they here? CPython 2 does not find it necessary to add this. (Things are changed a lot in Python 3, so I can't tell.)

I would revert if there is no compelling reason.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whether or not some random, CPython version from 20 years ago felt the need to add this, I was seeing test failures on at least one platform due to this. Again, like caused by race conditions. If the tests don’t pass on modern machines, how do you plan to validate the changes?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It turns out the root cause is that os.fstat (line 1099) fails on later Java versions unless --add-opens=java.base/java.io=ALL-UNNAMED is given. But since other parts of the patch add that, I think we're safe. I'll be able to test that.

Comment on lines +357 to +364
def tearDown(self):
# setUp installs a process-global opener with proxies disabled so these
# localhost tests ignore any external proxy environment. Restore the
# default opener afterwards: on Windows matrix runs the next urllib2
# network tests rely on the preserved proxy environment to reach
# external HTTP resources.
urllib2.install_opener(None)
super(TestUrlopen, self).tearDown()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the motivation is the proxied environment, even though this test does not use external network resources, because use of install_opener in setUp() messes up subsequent tests that do. And the change entails the shadow copy. :(

I think CPython is treating the same problem here: https://github.com/python/cpython/blob/8d21aa21f2cbc6d50aab3f420bb23be1d081dac4/Lib/test/test_urllib2_localnet.py#L470 . Might this be a better solution?

I think I would like longer term to update the lib-python version from CPython and remove the shadow. However, it has a lot of other differences: useful differences but with unknown impact.

@jeff5

jeff5 commented May 30, 2026

Copy link
Copy Markdown
Member

Just noting here that asm JARs are already at version 9.10.1 on Maven Central so I'll do an independent PR for that, instead of part 1 of this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Jython 2.7.5 release with Java 25 support

4 participants