Skip to content
This repository was archived by the owner on Dec 12, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Build

on:
push:
branches:
- main
tags:
- v*.*
pull_request:
workflow_dispatch:


jobs:
build_wheels:
runs-on: ubuntu-latest
strategy:
matrix:
# macos-13 is an intel runner, macos-14 is apple silicon
pyver: [ cp311, cp312 ]
steps:
- name: Checkout
uses: actions/checkout@v4

# Used to host cibuildwheel
- name: Setup python
uses: actions/setup-python@v5

- name: Set up QEMU
if: runner.os == 'Linux'
uses: docker/setup-qemu-action@v3
with:
platforms: all

- name: Build wheels
uses: pypa/cibuildwheel@v2.21.3
env:
# configure cibuildwheel to build native archs ('auto'), and some
# emulated ones
CIBW_BUILD: ${{matrix.pyver}}-*
CIBW_ARCHS_LINUX: auto aarch64
CIBW_BEFORE_ALL_LINUX: >
yum install -y java-11-openjdk-devel
CIBW_SKIP: '*-musllinux_*'

- uses: actions/upload-artifact@v4
with:
name: cibw-wheels-${{ matrix.pyver }}
path: ./wheelhouse/*.whl

build_sdist:
name: Build source distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Build sdist
run: pipx run build --sdist

- uses: actions/upload-artifact@v4
with:
name: cibw-sdist
path: dist/*.tar.gz

upload_pypi:
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/jpype1-ext
permissions:
id-token: write
# if: github.event_name == 'release' && github.event.action == 'published'
# or, alternatively, upload to PyPI on every tag starting with 'v' (remove on: release above to use this)
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/download-artifact@v4
with:
# unpacks all CIBW artifacts into dist/
pattern: cibw-*
path: dist
merge-multiple: true
- name: List artifacts
run: ls -lah dist/
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,4 @@ jacoco/
wheelhouse/
vc*.pdb
*.class
.venv
5 changes: 5 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ JPype

|implementation| |pyversions| |javaversions| |jvm| |platform| |license|

Why this fork for LocalStack?
--------------
We forked the jpype project to add a SIGTERM signal handler to be used in `LocalStack <https://github.com/localstack/localstack>`
We plan on contributing the changes upstream, should they be accepted.

JPype is a Python module to provide full access to Java from
within Python. It allows Python to make use of Java only libraries,
exploring and visualization of Java structures, development and testing
Expand Down
4 changes: 2 additions & 2 deletions native/common/jp_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -446,10 +446,10 @@ extern "C" JNIEXPORT void JNICALL Java_org_jpype_JPypeContext_onShutdown

static int interruptState = 0;
extern "C" JNIEXPORT void JNICALL Java_org_jpype_JPypeSignal_interruptPy
(JNIEnv *env, jclass cls)
(JNIEnv *env, jclass cls, jint signal)
{
interruptState = 1;
PyErr_SetInterrupt();
PyErr_SetInterruptEx((int) signal);
}

extern "C" JNIEXPORT void JNICALL Java_org_jpype_JPypeSignal_acknowledgePy
Expand Down
33 changes: 16 additions & 17 deletions native/java/org/jpype/JPypeSignal.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
**************************************************************************** */
package org.jpype;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
Expand All @@ -31,6 +30,17 @@ public class JPypeSignal

static Thread main;

static Object getSignalHandler(Class signalHandlerClazz, int signal) throws ClassNotFoundException {
return Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]
{
signalHandlerClazz
}, (proxy, method, args) -> {
main.interrupt();
interruptPy(signal);
return null;
});
}

static void installHandlers()
{
try
Expand All @@ -39,28 +49,17 @@ static void installHandlers()
Class SignalHandler = Class.forName("sun.misc.SignalHandler");
main = Thread.currentThread();
Method method = Signal.getMethod("handle", Signal, SignalHandler);

Object handler = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]
{
SignalHandler
}, new InvocationHandler()
{
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
main.interrupt();
interruptPy();
return null;
}
});
Object intr = Signal.getDeclaredConstructor(String.class).newInstance("INT");
method.invoke(null, intr, handler);
method.invoke(null, intr, getSignalHandler(SignalHandler, 2));
Object intrTerm = Signal.getDeclaredConstructor(String.class).newInstance("TERM");
Copy link
Member

Choose a reason for hiding this comment

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

This new SIGTERM handling seems the main part here

method.invoke(null, intrTerm, getSignalHandler(SignalHandler, 15));
} catch (InvocationTargetException | IllegalArgumentException | IllegalAccessException | InstantiationException | ClassNotFoundException | NoSuchMethodException | SecurityException ex)
{
// If we don't get the signal handler run without it. (ANDROID)
}
}

native static void interruptPy();
native static void interruptPy(int signal);

native static void acknowledgePy();
}
9 changes: 5 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ build-backend = "setuptools.build_meta"


[project]
name = "jpype1"
version = '1.5.2.dev0'
name = "jpype1-ext"
version = '0.0.2'
authors = [
{name = "Steve Menard", email = "devilwolf@users.sourceforge.net"},
]
maintainers = [
{name = "Luis Nell", email = "cooperate@originell.org"},
{name = "LocalStack Contributors", email = "info@localstack.cloud"},
]
description = "A Python to Java bridge"
description = "A Python to Java bridge - ext"
readme = "README.rst"
requires-python = ">=3.8"
license = {text = "License :: OSI Approved :: Apache Software License"}
Expand Down Expand Up @@ -52,7 +53,7 @@ tests = [


[project.urls]
homepage = "https://github.com/jpype-project/jpype"
homepage = "https://github.com/localstack/jpype"


[[tool.mypy.overrides]]
Expand Down
Loading