Issue2546

classification
Title: No way to add __doc__ to fields in Java-written module (?)
Type: behaviour Severity: minor
Components: Documentation Versions:
Milestone:
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: jeff.allen, stefan.richthofer
Priority: low Keywords:

Created on 2017-02-01.21:25:00 by stefan.richthofer, last changed 2018-03-12.23:24:02 by jeff.allen.

Messages
msg11056 (view) Author: Stefan Richthofer (stefan.richthofer) Date: 2017-02-01.21:25:00
Declaring

public static final PyString __doc__fieldName = Py.newString("blah");

seems not to add __doc__ to the field. Nor does

@ExposedGet(name = "fieldName", doc = "blah")

Not even a class-initializer (if field is PyObject-subclass)

{
fieldName.__setattr__("__doc__", Py.newString("blah"));
}

or using classDictInit

does the trick. Is it possible at all?
Even if it is somehow, there should be a more obvious way to do it.
msg11057 (view) Author: Stefan Richthofer (stefan.richthofer) Date: 2017-02-02.00:18:06
So, I figured out what needs to be done to support something like

public static final PyString __doc__fieldName = Py.newString("blah");

We would need to add a field to PyReflectedField:
public PyObject __doc__ = null;

In PyReflectedField.java append to _doget:

PyObject result = Py.java2py(value);
if (__doc__ != null) {
  try {
    result.__setattr__("__doc__", __doc__);
  } catch (PyException e) {}
}
return result;

Finally some modification in PyJavaType is required:
In init method change the part starting with for (Field field : fields) to the following:

        Map<String, CharSequence> doc_tmp = new HashMap<>();
        for (Field field : fields) {
            if (!declaredOnMember(baseClass, field)) {
                continue;
            }
            String fldname = field.getName();
            if (Modifier.isStatic(field.getModifiers())) {
                if (fldname.startsWith("__doc__") && fldname.length() > 7
                        && CharSequence.class.isAssignableFrom(field.getType())) {
                    String fname = fldname.substring(7).intern();
                    PyObject memb = dict.__finditem__(fname);
                    if (memb == null) {
                        memb = dict.__finditem__(normalize(fname));
                    }
                    if (memb != null) {// && memb instanceof PyReflectedFunction) {
                        CharSequence doc = null;
                        try {
                            doc = (CharSequence) field.get(null);
                        } catch (IllegalAccessException e) {
                            throw Py.JavaError(e);
                        }
                        if (memb instanceof PyReflectedFunction) {
                            ((PyReflectedFunction)memb).__doc__ = doc instanceof PyString ?
                                    (PyString) doc : new PyString(doc.toString());
                        } else if (memb instanceof PyReflectedField) {
                            try {
                                ((PyReflectedField)memb).__doc__ = doc instanceof PyString ?
                                        (PyString) doc : new PyString(doc.toString());
                            } catch (Exception e) {
                                System.out.println(444+"  "+e);
                            }
                        }
                    } else {
                        try {
                            doc_tmp.put(normalize(fname), (CharSequence) field.get(null));
                        } catch (IllegalAccessException e) {
                            throw Py.JavaError(e);
                        }
                    }
                }
            }
            if (dict.__finditem__(normalize(fldname)) == null) {
                PyReflectedField fld = new PyReflectedField(field);
                CharSequence doc = doc_tmp.get(normalize(fldname));
                if (doc != null) fld.__doc__ = doc instanceof PyString ?
                        (PyString) doc : new PyString(doc.toString());
                dict.__setitem__(normalize(fldname), fld);
            }
        }

If there are no concerns and tests go fine I'd be for adding this doc-feature.
msg11066 (view) Author: Stefan Richthofer (stefan.richthofer) Date: 2017-02-02.16:56:31
The described approach fails if an object has read-only __doc__ attribute.
E.g. for boolean fields. Anyway, adding __doc__ to the field-value isn't good if a value is shared between objects. Jython should better get the doc directly from the PyReflectedField-object if some_attribute.__doc__ is evaluated.

Any suggestions how to achieve this?
msg11788 (view) Author: Jeff Allen (jeff.allen) Date: 2018-03-12.23:24:01
Stefan: I may be misunderstanding what you are expecting. Searching for an example, I find:

https://hg.python.org/jython/file/tip/src/org/python/modules/_io/PyFileIO.java#l63

It is true that my first attempts to have Jython produce that text were unsatisfactory:

>>> import io
>>> f = io.open('x.tmp', 'wb', buffering=0)
>>> type(f)
<type '_io.FileIO'>
>>> help(f.mode)
no Python documentation found for 'wb'

But it actually appears when you ask for help on the FileIO object:
>>> help(f)
Help on FileIO object:

class FileIO(_RawIOBase)
 |  Method resolution order:
 |      FileIO
 |      _RawIOBase
 |      _IOBase
 |      __builtin__.object
 |
 |  Methods defined here:
...
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  closefd
 |      True if the file descriptor will be closed
 |
 |  mode
 |      String giving the file mode: 'rb', 'rb+', or 'wb'
 |
...

This is similar in CPython.
History
Date User Action Args
2018-03-12 23:24:02jeff.allensetnosy: + jeff.allen
messages: + msg11788
2017-02-02 16:56:32stefan.richthofersetmessages: + msg11066
2017-02-02 00:18:07stefan.richthofersetmessages: + msg11057
2017-02-01 21:25:00stefan.richthofercreate