Skip to content
This repository has been archived by the owner on Sep 20, 2023. It is now read-only.

Update options for JPype 0.7.0 #85

Merged
merged 1 commit into from
Jun 28, 2019

Conversation

Thrameos
Copy link
Contributor

Corrects issues with -server option. Not all JVM accept that option.

Copy link
Owner

@laughingman7743 laughingman7743 left a comment

Choose a reason for hiding this comment

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

@Thrameos Thanks!

@laughingman7743 laughingman7743 merged commit b3a42c6 into laughingman7743:master Jun 28, 2019
@laughingman7743
Copy link
Owner

laughingman7743 commented Jun 28, 2019

self = <pyathenajdbc.converter.JDBCTypeConverter object at 0x7fdd0c098cd0>
    def __init__(self):
        types = jpype.java.sql.Types
        self._jdbc_type_name_mappings = dict()
        self._jdbc_type_code_mappings = dict()
        for field in types.__javaclass__.getClassFields():
>           self._jdbc_type_name_mappings[field.getName()] = field.getStaticAttribute()
E           AttributeError: '_jpype.PyJPField' object has no attribute 'getStaticAttribute'

How do I reference getStaticAttribute? 🤔

@Thrameos
Copy link
Contributor Author

That method was previously an internal private so it likely wasn't intended to be used directly thus it did not get preserved. PyJPField is an descriptor now so the nearest function would be __get__. All types basically got mapped into the same functionality as python that Java methods are the same as functions and Java fields are the same as properties.

There is one other place were I have seen people using internals that seems to crop up. Under 0.7.0 the exceptions are mapped directly to Python, but they were indirectly mapped in 0.6.3. The use of JException() was the safe pattern in the old version and should work in both, but most people got directly into the argument list. If you want to require 0.7.0 it is easy as rather than calling the wrapper you simple catch the Java type (or catch from a rethrow.)

Ie.

0.6.3:

    try:
        # some code
    except  JavaException as exc:
        if issubclass(exc.__javaclass__, SomeJavaException):
            # handle it

Which is bad because it is going into the private methods.

The pattern for 0.6.3 was supposed to be (though honestly I am not sure if it worked as some things were buggy)

   try: 
       # some code
   except JException(SomeJavaException):
       # handle it.

Starting from 0.7.0, the exceptions are all Python exceptions so they can be caught directly.

   try: 
       # some code
   except SomeJavaException:
       # handle it.

JException is still the base class and can be used to catch and redirect to a handling routine.

I see this issue at util.py but as I can't run the test bench I didn't want to try to fix it there.

@laughingman7743
Copy link
Owner

It seems that 0.7.0 can be written fluently.
It is a great improvement. 👍

@laughingman7743
Copy link
Owner

The return value of field.__get__ is <method-wrapper '__get__' of _jpype.PyJPField object at 0x112fcb630>. 🤔

@Thrameos
Copy link
Contributor Author

Well it is a descriptor so it should be accessed as such.

Thus

types = jpype.java.sql.Types
_jdbc_type_name_mappings = dict()
for field in types.__javaclass__.getClassFields():
     _jdbc_type_name_mappings[field.getName()] = field.getStaticAttribute()
print(_jdbc_type_name_mappings)

Would become

types = jpype.java.sql.Types
_jdbc_type_name_mappings = dict()
for field in types.__javaclass__.getClassFields():
     _jdbc_type_name_mappings[field.getName()] = getattr(types,field.getName())
print(_jdbc_type_name_mappings)

Because to get the value of a Python field is to call getattr with the name of the field. After all types.TINYINT is a the value -6, thus getattr(types, 'TINYINT') would also give -6. Thus in general the translation should always be to "what would I do to a python object to perform this action?" If you wanted to copy all the fields of an object you would find the fields and access them using getattr.

Of course this still isn't perfect as we are still accessing the private __javaclass__ which is another private item. So how would be get the names of each static field from a Java type. There is no such concept in Python, so lets turn to Java. If this were Java, I would call "java.sql.Types.class.getFields()" (or getDeclaredFields if I want everything at one level including privates) then skip anything which was not a static field using getModifiers. So lets do exactly that. The java.lang.Class for a type is called class_, and the modifiers API is all accessible.

modifier = jpype.java.lang.reflect.Modifier
types = jpype.java.sql.Types
_jdbc_type_name_mappings = dict()
for field in types.class_.getFields():
    if modifier.isStatic(field.getModifiers()):
        _jdbc_type_name_mappings[field.getName()] = getattr(types, field.getName())
print(_jdbc_type_name_mappings)

Simple and now without touching anyone's privates.

{'BIT': -7, 'TINYINT': -6, 'SMALLINT': 5, 'INTEGER': 4, 'BIGINT': -5, 'FLOAT': 6, 'REAL': 7, 'DOUBLE': 8, 'NUMERIC': 2, 'DECIMAL': 3, 'CHAR': 1, 'VARCHAR': 12, 'LONGVARCHAR': -1, 'DATE': 91, 'TIME': 92, 'TIMESTAMP': 93, 'BINARY': -2, 'VARBINARY': -3, 'LONGVARBINARY': -4, 'NULL': 0, 'OTHER': 1111, 'JAVA_OBJECT': 2000, 'DISTINCT': 2001, 'STRUCT': 2002, 'ARRAY': 2003, 'BLOB': 2004, 'CLOB': 2005, 'REF': 2006, 'DATALINK': 70, 'BOOLEAN': 16, 'ROWID': -8, 'NCHAR': -15, 'NVARCHAR': -9, 'LONGNVARCHAR': -16, 'NCLOB': 2011, 'SQLXML': 2009, 'REF_CURSOR': 2012, 'TIME_WITH_TIMEZONE': 2013, 'TIMESTAMP_WITH_TIMEZONE': 2014}

Better yet, running the same code with 0.6.3 gives the same answer.

@laughingman7743
Copy link
Owner

Thanks! It was really easy to understand.

Better yet, running the same code with 0.6.3 gives the same answer.

It is wonderful. I will try to fix it to work with 0.7.0 and 0.6.3.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants