Skip to content

Commit

Permalink
"Generic" JArray support
Browse files Browse the repository at this point in the history
  • Loading branch information
astrelsky committed Sep 2, 2024
1 parent 66f8c6c commit 18313e3
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 2 deletions.
1 change: 1 addition & 0 deletions jpype/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ def initializeResources():
_jpype._type_classes[object] = _jpype._java_lang_Object
_jpype._type_classes[_jpype.JString] = _jpype._java_lang_String
_jpype._type_classes[_jpype.JObject] = _jpype._java_lang_Object
_jpype._type_classes[_jpype.JClass] = _jpype._java_lang_Class
_jinit.runJVMInitializers()

_jpype.JClass('org.jpype.JPypeKeywords').setKeywords(
Expand Down
16 changes: 16 additions & 0 deletions jpype/_jarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ def __new__(cls, tp, dims=1):
def of(cls, array, dtype=None):
return _jpype.arrayFromBuffer(array, dtype)

def __class_getitem__(cls, key):
if key is _jpype.JClass:
# explicit check for JClass
# _toJavaClass cannot be used
# passing int, float, etc is not allowed
key = _jpype._java_lang_Class

Check warning on line 100 in jpype/_jarray.py

View check run for this annotation

Codecov / codecov/patch

jpype/_jarray.py#L100

Added line #L100 was not covered by tests
if isinstance(key, (str, _jpype._java_lang_Class)):
key = _jpype.JClass(key)

Check warning on line 102 in jpype/_jarray.py

View check run for this annotation

Codecov / codecov/patch

jpype/_jarray.py#L102

Added line #L102 was not covered by tests
if isinstance(key, _jpype.JClass):
return type(key[0])

Check warning on line 104 in jpype/_jarray.py

View check run for this annotation

Codecov / codecov/patch

jpype/_jarray.py#L104

Added line #L104 was not covered by tests
raise TypeError("Cannot instantiate unspecified array type")


class _JArrayProto(object):

Expand All @@ -104,6 +116,10 @@ def __iter__(self):
def __reversed__(self):
for elem in self[::-1]:
yield elem

def __contains__(self, item):
# "in" works without this but this should be more efficient
return _jpype.JClass("java.util.Arrays").asList(self).contains(item)

Check warning on line 122 in jpype/_jarray.py

View check run for this annotation

Codecov / codecov/patch

jpype/_jarray.py#L122

Added line #L122 was not covered by tests

def clone(self):
""" Clone the Java array.
Expand Down
43 changes: 43 additions & 0 deletions jpype/_jarray.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# *****************************************************************************
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# See NOTICE file for details.
#
# *****************************************************************************
import abc
import collections.abc
import typing


__all__ = ['JArray']


T = typing.TypeVar('T')


class _JArrayGeneric(collections.abc.Sequence[T]):

@abc.abstractmethod
def __setitem__(self, index, value):
...


class JArray(_JArrayGeneric[T], metaclass=abc.ABCMeta):

def __new__(cls, tp, dims=1):
...

@classmethod
def of(cls, array, dtype=None):
...
5 changes: 5 additions & 0 deletions jpype/_jclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ def __new__(cls, jc, loader=None, initialize=True):

# Pass to class factory to create the type
return _jpype._getClass(jc)

@classmethod
def __class_getitem__(cls, index):
# enables JClass[1] to get a Class[]
return JClass("java.lang.Class")[index]


class JInterface(_jpype._JObject, internal=True): # type: ignore[call-arg]
Expand Down
5 changes: 3 additions & 2 deletions native/python/pyjp_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -728,8 +728,9 @@ static PyObject *PyJPClass_array(PyJPClass *self, PyObject *item)

if (self->m_Class == NULL)
{
PyErr_Format(PyExc_TypeError, "Cannot instantiate unspecified array type");
return NULL;
PyObject *res = PyObject_CallMethod((PyObject *)self, "__class_getitem__", "O", item);
Py_DECREF(item);
return res;
}

if (PyIndex_Check(item))
Expand Down
12 changes: 12 additions & 0 deletions test/jpypetest/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ def testShortcut(self):
# Check Objects
self.assertEqual(JString[5].getClass(), JArray(JString)(5).getClass())
self.assertEqual(JObject[5].getClass(), JArray(JObject)(5).getClass())
self.assertEqual(JClass[5].getClass(), JArray(JClass)(5).getClass())

# Test multidimensional
self.assertEqual(JDouble[5, 5].getClass(), JArray(JDouble, 2)(5).getClass())
Expand All @@ -601,3 +602,14 @@ def testShortcut(self):
def testJArrayIndex(self):
with self.assertRaises(TypeError):
jpype.JArray[10]

def testJArrayGeneric(self):
self.assertEqual(type(JObject[0]), JArray(JObject))

def testJArrayGeneric_Init(self):
Arrays = JClass("java.util.Arrays")
self.assertTrue(Arrays.equals(JObject[0], JArray(JObject)(0)))

def testJArrayInvalidGeneric(self):
with self.assertRaises(TypeError):
jpype.JArray[object]

0 comments on commit 18313e3

Please sign in to comment.