Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into cleanup-deephaven-p…
Browse files Browse the repository at this point in the history
…ython-dependencies
  • Loading branch information
devinrsmith committed Jun 24, 2022
2 parents 414e8b6 + d436ad0 commit c0b8b22
Show file tree
Hide file tree
Showing 99 changed files with 1,942 additions and 2,334 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
/README.md @chipkent @rcaudy @margaretkennedy
/TRIAGE.md @chipkent
/licenses @chipkent
/docker @devinrsmith @jcferretti
12 changes: 11 additions & 1 deletion .github/workflows/publish-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ name: Publish CI

on:
push:
branches: [ 'release/v*' ]
branches: [ 'main', 'release/v*' ]
pull_request:
branches: [ main ]

jobs:
publish:
Expand Down Expand Up @@ -35,7 +37,15 @@ jobs:
echo "org.gradle.java.installations.paths=${{ steps.setup-java-11.outputs.path }},${{ steps.setup-java-17.outputs.path }}," >> gradle.properties
cat gradle.properties
- name: Publish to Maven Local
if: ${{ !startsWith(github.ref, 'refs/heads/release/v') }}
uses: burrunan/gradle-cache-action@v1
with:
arguments: publishToMavenLocal -x signMavenJavaPublication -x signMyPlatformPublication
gradle-version: wrapper

- name: Publish
if: ${{ startsWith(github.ref, 'refs/heads/release/v') }}
uses: burrunan/gradle-cache-action@v1
with:
job-id: publish
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending
*/
package io.deephaven.integrations.python;

import io.deephaven.util.annotations.ScriptApi;
import org.jpy.PyObject;

import java.util.function.BiFunction;
import java.util.function.BinaryOperator;

import static io.deephaven.integrations.python.PythonUtils.pyApplyFunc;

/**
* A {@link BiFunction} implementation which calls a Python callable.
*
* @param <T> input argument class
* @param <U> input argument class
*/
@SuppressWarnings("unused")
@ScriptApi
public class PythonBiFunction<T, U, R> implements BiFunction<T, U, R> {
private final PyObject pyCallable;
private final Class<R> classOut;

/**
* Creates a {@link BiFunction} which calls a Python function.
*
* @param pyCallable The python object providing the function - must either be callable or have an {@code apply}
* attribute which is callable.
* @param classOut The specific Java class expected to be returned by the {@link #apply(Object, Object)} method.
* This should be the result of converting or unwrapping the output of {@code pyCallable}.
*/
public PythonBiFunction(final PyObject pyCallable, final Class<R> classOut) {
this.pyCallable = pyApplyFunc(pyCallable);
this.classOut = classOut;
}

@Override
public R apply(T t, U u) {
PyObject wrapped = PythonObjectWrapper.wrap(t);
PyObject wrappedOther = PythonObjectWrapper.wrap(u);
PyObject out = pyCallable.call("__call__", wrapped, wrappedOther);
return PythonValueGetter.getValue(out, classOut);
}


public static class PythonBinaryOperator<T> extends PythonBiFunction<T, T, T> implements BinaryOperator<T> {
/**
* Creates a {@link PythonBinaryOperator} which calls a Python function.
*
* @param pyCallable The python object providing the function - must either be callable or have an {@code apply}
* attribute which is callable.
* @param classOut The specific Java class expected to be returned by the {@link #apply(Object, Object)} method.
* This should be the result of converting or unwrapping the output of {@code pyCallable}.
*/
public PythonBinaryOperator(PyObject pyCallable, Class<T> classOut) {
super(pyCallable, classOut);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@

import io.deephaven.util.annotations.ScriptApi;
import org.jpy.PyObject;

import java.util.function.Function;
import io.deephaven.util.QueryConstants;
import java.util.function.UnaryOperator;

import static io.deephaven.integrations.python.PythonUtils.pyApplyFunc;

Expand All @@ -15,141 +16,47 @@
*
* @param <T> input argument class
*/
@SuppressWarnings("unused")
@ScriptApi
public class PythonFunction<T> implements Function<T, Object> {
public class PythonFunction<T, R> implements Function<T, R> {
private final PyObject pyCallable;
private final Function<PyObject, Object> getter;
private final Class<R> classOut;

/**
* Creates a {@link Function} which calls a Python function.
*
* @param pyObjectIn the python object providing the function - must either be callable or have an `apply` attribute
* which is callable.
* @param classOut the specific java class to interpret the return for the method. Note that this is probably only
* really useful if `classOut` is one of String, double, float, long, int, short, byte, or boolean.
* Otherwise, the return element will likely just remain PyObject, and not be particularly usable inside
* Java.
* @param pyCallable The python object providing the function - must either be callable or have an {@code apply}
* attribute which is callable.
* @param classOut The specific Java class expected to be returned by the {@link #apply(Object)} method. This should
* be the result of converting or unwrapping the output of {@code pyCallable}.
*
*/
public PythonFunction(final PyObject pyObjectIn, final Class classOut) {
public PythonFunction(final PyObject pyCallable, final Class<R> classOut) {

pyCallable = pyApplyFunc(pyObjectIn);
this.pyCallable = pyApplyFunc(pyCallable);
this.classOut = classOut;

// Note: Potentially important types omitted -simply because handling from python is not super clear:
// Character/char, BigInteger, BigDecimal
if (CharSequence.class.isAssignableFrom(classOut)) {
getter = new StringValueGetter();
} else if (classOut.equals(Double.class) || classOut.equals(double.class)) {
getter = new DoubleValueGetter();
} else if (classOut.equals(Float.class) || classOut.equals(float.class)) {
getter = new FloatValueGetter();
} else if (classOut.equals(Long.class) || classOut.equals(long.class)) {
getter = new LongValueGetter();
} else if (classOut.equals(Integer.class) || classOut.equals(int.class)) {
getter = new IntValueGetter();
} else if (classOut.equals(Short.class) || classOut.equals(short.class)) {
getter = new ShortValueGetter();
} else if (classOut.equals(Byte.class) || classOut.equals(byte.class)) {
getter = new ByteValueGetter();
} else if (classOut.equals(Boolean.class) || classOut.equals(boolean.class)) {
getter = new BoolValueGetter();
} else {
getter = new ObjectValueGetter(); // warning or something? This will likely be useless.
}
}

@Override
public Object apply(T t) {
PyObject out = pyCallable.call("__call__", t);
return getter.apply(out);
}

static class ObjectValueGetter implements Function<PyObject, Object> {
@Override
public Object apply(PyObject valueIn) {
if (valueIn == null) {
return null;
}
return valueIn.getObjectValue();
}
}

static class StringValueGetter implements Function<PyObject, Object> {
@Override
public Object apply(PyObject valueIn) {
if (valueIn == null) {
return null;
}
return valueIn.getStringValue();
}
}

static class DoubleValueGetter implements Function<PyObject, Object> {
@Override
public Object apply(PyObject valueIn) {
if (valueIn == null) {
return QueryConstants.NULL_DOUBLE;
}
return valueIn.getDoubleValue();
}
}

static class FloatValueGetter implements Function<PyObject, Object> {
@Override
public Object apply(PyObject valueIn) {
if (valueIn == null) {
return QueryConstants.NULL_FLOAT;
}
return (float) valueIn.getDoubleValue(); // NB: should there be a getFloatValue() in jpy?
}
}

static class LongValueGetter implements Function<PyObject, Object> {
@Override
public Object apply(PyObject valueIn) {
if (valueIn == null) {
return QueryConstants.NULL_LONG;
}
return valueIn.getLongValue();
}
}

static class IntValueGetter implements Function<PyObject, Object> {
@Override
public Object apply(PyObject valueIn) {
if (valueIn == null) {
return QueryConstants.NULL_INT;
}
return valueIn.getIntValue();
}
}

static class ShortValueGetter implements Function<PyObject, Object> {
@Override
public Object apply(PyObject valueIn) {
if (valueIn == null) {
return QueryConstants.NULL_SHORT;
}
return (short) valueIn.getIntValue(); // NB: should there be a getShortValue() in jpy?
}
}

static class ByteValueGetter implements Function<PyObject, Object> {
@Override
public Object apply(PyObject valueIn) {
if (valueIn == null) {
return QueryConstants.NULL_BYTE; // NB: should there be a getByteValue() in jpy?
}
return (byte) valueIn.getIntValue();
}
}

static class BoolValueGetter implements Function<PyObject, Object> {
@Override
public Object apply(PyObject valueIn) {
if (valueIn == null) {
return null;
}
return valueIn.getBooleanValue();
public R apply(T t) {
PyObject wrapped = PythonObjectWrapper.wrap(t);
PyObject out = pyCallable.call("__call__", wrapped);
return PythonValueGetter.getValue(out, classOut);
}

public static class PythonUnaryOperator<T> extends PythonFunction<T, T> implements UnaryOperator<T> {

/**
* Creates a {@link UnaryOperator} which calls a Python function.
*
* @param pyCallable The python object providing the function - must either be callable or have an {@code apply}
* attribute which is callable.
* @param classOut The specific Java class expected to be returned by the {@link #apply(Object)} method. This
* should be the result of converting or unwrapping the output of {@code pyCallable}.
*/
public PythonUnaryOperator(PyObject pyCallable, Class<T> classOut) {
super(pyCallable, classOut);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending
*/
package io.deephaven.integrations.python;

import org.jpy.PyModule;
import org.jpy.PyObject;

/**
* This is a helper class for wrapping a Java object in a Python wrapper and unwrapping a Python wrapper to a raw Java
* object.
*/
public class PythonObjectWrapper {
private static final PyModule PY_WRAPPER_MODULE = PyModule.importModule("deephaven._wrapper");

/**
* Unwrap a Python object to return the wrapped Java object.
*
* @param t An instance of {@link PyObject}.
* @return The wrapped Java object.
*/
public static Object unwrap(PyObject t) {
// noinspection ConstantConditions
return PY_WRAPPER_MODULE.call("unwrap", t).getObjectValue();
}

/**
* Wrap a raw Java object with a Python wrapper if one exists for its type, otherwise return a JPY mapped Python
* object.
*
* @param t A Java object.
* @return A {@link PyObject} instance representing the Python wrapper object.
*/
public static PyObject wrap(Object t) {
// noinspection ConstantConditions
return PY_WRAPPER_MODULE.call("wrap_j_object", t);
}
}
Loading

0 comments on commit c0b8b22

Please sign in to comment.