8000 Add object introspection functions by ctrueden · Pull Request #78 · scijava/scyjava · GitHub
[go: up one dir, main page]

Skip to content

Add object introspection functions #78

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 41 commits into from
Apr 29, 2025
Merged
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
0a8141c
Add some functions for Java object introspection
ctrueden Mar 26, 2025
7b8a6c4
Update methods() functionality
ian-coccimiglio Mar 27, 2025
fe0bfe3
Make progress on introspection methods
ian-coccimiglio Mar 27, 2025
25d769e
Make linter happy
ian-coccimiglio Mar 27, 2025
1a0fd71
Add source code reporting to methods() function
ian-coccimiglio Mar 27, 2025
640d57d
Implement fields introspection function
ian-coccimiglio Mar 27, 2025
aa3996c
Add partials, refactor, add java_source function
ian-coccimiglio Mar 28, 2025
9352ff6
Refactor introspection code
ian-coccimiglio Mar 28, 2025
fe60217
Add test cases for introspection functions
ian-coccimiglio Mar 28, 2025
7293d23
Lint code
ian-coccimiglio Mar 28, 2025
4123078
Improve introspection function documentation
ian-coccimiglio Mar 31, 2025
3533446
Add docstring to test_introspection.py
ian-coccimiglio Mar 31, 2025
9516a72
Wrap long line
ctrueden Apr 2, 2025
6520223
Increment minor version digit
ctrueden Apr 2, 2025
363e7bc
Alphabetize introspection imports
ctrueden Apr 2, 2025
c8afba4
Shorten introspection to introspect
ctrueden Apr 2, 2025
6bfec82
Add toplevel docstrings to test files
ctrueden Apr 2, 2025
37bd92e
Fix naming of versions test file
ctrueden Apr 2, 2025
5f883f1
Fix type hints to work with Python 3.8
ctrueden Apr 2, 2025
6282d8c
CI: test Python 3.13 support
ctrueden Apr 2, 2025
bded14f
Rename find_java function to jreflect
ctrueden Apr 2, 2025
0778a89
Add missing is_j* type methods to README
ctrueden Apr 2, 2025
21ffae9
Use imperative tense for function docstrings
ctrueden Apr 2, 2025
bb06ed1
Wrap >88 lines, and make quoting more consistent
ctrueden Apr 2, 2025
553d552
Add introspection functions to the README
ctrueden Apr 2, 2025
bf2ee82
Improve get_version method
ctrueden Apr 24, 2025
2d44fed
Test a little further into the GitHub source paths
ctrueden Apr 24, 2025
8846ce5
Tweak management of multiple endpoints
ctrueden Apr 24, 2025
a31701b
Rename java_source method to jsource
ctrueden Apr 24, 2025
2713b6c
Make jreflect function more powerful
ctrueden Apr 24, 2025
92d7fb1
Split pretty-print functions to own subpackage
ctrueden Apr 25, 2025
30bd4d3
Hide non-public scijava.config attrs
ctrueden Apr 25, 2025
a537c00
Hide non-public scyjava.inspect attrs
ctrueden Apr 25, 2025
cea10cd
Use jimport naming convention for Java types
ctrueden Apr 25, 2025
3a46f1b
Make output writer configurable
ctrueden Apr 25, 2025
5fe1461
Replace print statements with logger calls
ctrueden Apr 25, 2025
2f11f0d
Add unit test for inspect.members function
ctrueden Apr 25, 2025
f4266c4
Ensure submodules are directly available
ctrueden Apr 25, 2025
1d9b507
Let jsource also find Java library source code
ctrueden Apr 25, 2025
5c06747
Be less aggressive with source code detection
ctrueden Apr 25, 2025
e5e9cab
Add test for jreflect constructors
ctrueden Apr 29, 2025
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
Prev Previous commit
Next Next commit
Make progress on introspection methods
  • Loading branch information
ian-coccimiglio authored and ctrueden committed Apr 2, 2025
commit fe0bfe391d24a7b4b37f2b38e2ebb138c8c9d41b
105 changes: 88 additions & 17 deletions src/scyjava/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ def find_java_methods(data) -> list[dict[str, Any]]:
returning a table of its available methods.

:param data: The object or class to inspect.
:return: List of table rows with columns "name", "arguments", and "returns".
:return: List of table rows with columns "name", "static", "arguments", and "returns".
"""

if not isjava(data):
Expand All @@ -357,14 +357,17 @@ def find_java_methods(data) -> list[dict[str, Any]]:
# })

table = []
Modifier = jimport("java.lang.reflect.Modifier")

for m in methods:
name = m.getName()
args = [c.getName() for c in m.getParameterTypes()]
mods = Modifier.isStatic(m.getModifiers())
returns = m.getReturnType().getName()
table.append(
{
"name": name,
"static": mods,
"arguments": args,
"returns": returns,
}
Expand All @@ -374,7 +377,31 @@ def find_java_methods(data) -> list[dict[str, Any]]:
return sorted_table


def map_syntax(base_type):
# TODO
def find_java_fields(data) -> list[dict[str, Any]]:
"""
Use Java reflection to introspect the given Java object,
returning a table of its available fields.

:param data: The object or class to inspect.
:return: List of table rows with columns "name", "arguments", and "returns".
"""
if not isjava(data):
raise ValueError("Not a Java object")

cls = data if jinstance(data, "java.lang.Class") else jclass(data)

fields = cls.getFields()
table = []

for f in fields:
name = f.getName()
table.append(name)

return table


def _map_syntax(base_type):
"""
Maps a java BaseType annotation (see link below) in an Java array
to a specific type with an Python interpretable syntax.
Expand All @@ -385,7 +412,7 @@ def map_syntax(base_type):
"[C": "char[]",
"[D": "double[]",
"[F": "float[]",
"[C": "int[]",
"[I": "int[]",
"[J": "long[]",
"[L": "[]", # array
"[S": "short[]",
Expand All @@ -394,33 +421,77 @@ def map_syntax(base_type):

if base_type in basetype_mapping:
return basetype_mapping[base_type]
# Handle the case of a returned array of an object
elif base_type.__str__().startswith("[L"):
return base_type.__str__()[2:-1] + "[]"
else:
return base_type


def _make_pretty_string(entry, offset):
"""
Prints the entry with a specific formatting and aligned style
:param entry: Dictionary of class names, modifiers, arguments, and return values.
:param offset: Offset between the return value and the method.
"""

# A star implies that the method is a static method
return_val = f'{entry["returns"].__str__():<{offset}}'
# Handle whether to print static/instance modifiers
obj_name = f'{entry["name"]}'
modifier = f'{"*":>4}' if entry["static"] else f'{"":>4}'

# Handle methods with no arguments
if not entry["arguments"]:
return f"{return_val} {modifier} = {obj_name}()\n"
else:
arg_string = ", ".join([r.__str__() for r in entry["arguments"]])
return f"{return_val} {modifier} = {obj_name}({arg_string})\n"


# TODO
def fields(data) -> str:
"""
Writes data to a printed field names with the field value.
:param data: The object or class to inspect.
"""
table = find_java_fields(data)

all_fields = ""
################
# FILL THIS IN #
################

print(all_fields)


# TODO
def attrs(data):
"""
Writes data to a printed field names with the field value. Alias for `fields(data)`.
:param data: The object or class to inspect.
"""
fields(data)


def methods(data) -> str:
"""
Writes data to a printed string of class methods with inputs, static modifier, arguments, and return values.

:param data: The object or class to inspect.
"""
table = find_java_methods(data)

offset = max(list(map(lambda l: len(l["returns"]), table)))
all_methods = ""

for entry in table:
entry["returns"] = map_syntax(entry["returns"])
entry["arguments"] = [map_syntax(e) for e in entry["arguments"]]
entry["returns"] = _map_syntax(entry["returns"])
entry["arguments"] = [_map_syntax(e) for e in entry["arguments"]]
entry_string = _make_pretty_string(entry, offset)
all_methods += entry_string

if not entry["arguments"]:
all_methods = (
all_methods
+ f'{entry["returns"].__str__():<{offset}} = {entry["name"]}()\n'
)
else:
arg_string = ", ".join([r.__str__() for r in entry["arguments"]])
all_methods = (
all_methods
+ f'{entry["returns"].__str__():<{offset}} = {entry["name"]}({arg_string})\n'
)
# 4 added to align the asterisk with output.
print(f'{"":<{offset+4}}* indicates a static method')
print(all_methods)


Expand Down
0