Issue2515

classification
Title: typing module doesn't import
Type: Severity: normal
Components: Library Versions: Jython 2.7
Milestone: Jython 2.7.1
process
Status: pending Resolution: fixed
Dependencies: Superseder:
Assigned To: stefan.richthofer Nosy List: stefan.richthofer, zyasoft
Priority: normal Keywords:

Created on 2016-08-20.14:23:14 by stefan.richthofer, last changed 2017-01-09.09:51:33 by stefan.richthofer.

Messages
msg10900 (view) Author: Stefan Richthofer (stefan.richthofer) Date: 2016-08-20.14:23:13
I am currently experimenting with Python 2.7. style type-comments from Pep 484. (I'd like to use it for type-checking and maybe later to auto generate Java interfaces for object coercion with Jython). However Jython fails to import the typing module with the following error:

java -jar jython.jar typetest.py
Traceback (most recent call last):
  File "typetest.py", line 12, in <module>
    import typing
  File "/usr/local/lib/python2.7/dist-packages/typing.py", line 345, in <module>
    class Any(Final):
  File "/usr/local/lib/python2.7/dist-packages/typing.py", line 332, in __new__
    cls.assert_no_subclassing(bases)
  File "/usr/local/lib/python2.7/dist-packages/typing.py", line 100, in assert_no_subclassing
    if isinstance(base, cls):
RuntimeError: maximum recursion depth exceeded (Java StackOverflowError)


- no C-extension is involved
- the module _is_ Python 2.7. compatible and the code runs fine with CPython 2.7.

I'll continue to investigate, but if someone has a clue, please share ;)
msg10909 (view) Author: Jim Baker (zyasoft) Date: 2016-08-24.20:30:02
Simple enough - the typing module found a bug in our implementation.
msg11007 (view) Author: Stefan Richthofer (stefan.richthofer) Date: 2017-01-06.15:40:08
I nailed it down to an issue with __instancecheck__ in newstyle (Meta-)classes:


class Foo(object):
    pass

class BarMeta(object):
	def __instancecheck__(self, obj):
		pass

isinstance(Foo, BarMeta) # fails with maximum recursion depth exceeded


- This also fails if Foo is oldstyle
- This passes if Bar is oldstyle
msg11008 (view) Author: Stefan Richthofer (stefan.richthofer) Date: 2017-01-06.18:05:42
It seems the issue is in Py.dispatchToChecker. It looks like the checkers (__instancecheck, __subclasschecke__ ...) are not applied on the metaclass like it should be, but instead on the class itself. However I wonder how this wouldn't cause much more issues than it seems to. IMO Py.dispatchToChecker should do something like

        PyObject meta = cls.__findattr__("__metaclass__");
        if (meta == null) {
        	return null;
        }
        PyObject checker = meta.__findattr__(checkerName);
        if (checker == null) {
            return null;
        }
        return checker.__call__(cls, checkerArg);


rather than currently

        PyObject checker = cls.__findattr__(checkerName);
        if (checker == null) {
            return null;
        }
        return checker.__call__(checkerArg);

If I apply that, import typing proceeds somewhat further, but runs into different issues. tbc...
msg11009 (view) Author: Stefan Richthofer (stefan.richthofer) Date: 2017-01-07.15:49:31
Next issue boils down to

getattr(types.TypeType, "__abstractmethods__")

should raise AttributeError: __abstractmethods__
(like it does in CPython)

but in Jython it returns
<attribute '__abstractmethods__' of 'type' objects>

Code in abc.py expects
getattr(types.TypeType, "__abstractmethods__", set())
to be iterable, which Jython's result isn't. In CPython, the default-result set() is triggered by the AttributeError, so provides an empty iterable. Once <type 'type'> is in a base (like happens in typing.py), Jython lets abc.py crash with
'getset_descriptor' object is not iterable

Now I try to figure out where and why Jython inserts __abstractmethods__ into TypeType...
msg11010 (view) Author: Stefan Richthofer (stefan.richthofer) Date: 2017-01-07.18:31:07
Rewriting PyType.getAbstractmethods to

    public PyObject getAbstractmethods() {
        PyObject result = dict.__finditem__("__abstractmethods__");
        if (result == null || result instanceof PyDataDescr) {
            noAttributeError("__abstractmethods__");
        }
        return result;
    }

i.e. inserting ' || result instanceof PyDataDescr'
seems to solve it. I also checked other magic attributes (e.g. __module__) that are backed by getset_descriptors and __abstractmethods__ seems to be the only one that behaves differently from CPython, so this special-case-fix should be ultimate for the whole issue.

typing.py imports fine with the described fixes. Just running regrtests right now - fingers crossed.
Also: I suppose there were several newer versions of typing.py even for Python 2.7 than I tested with. So I will also investigate these, but suppose this issue is basically done now.
msg11011 (view) Author: Stefan Richthofer (stefan.richthofer) Date: 2017-01-09.09:51:33
Fixed as of https://github.com/jythontools/jython/commit/600030f84f175dd0fab2e8a06b137e2d02bd0486

Tested with typing 3.5.2.2 and 3.5.3.0.
History
Date User Action Args
2017-01-09 09:51:33stefan.richthofersetstatus: open -> pending
resolution: accepted -> fixed
messages: + msg11011
2017-01-07 18:31:07stefan.richthofersetmessages: + msg11010
milestone: Jython 2.7.2 -> Jython 2.7.1
2017-01-07 15:49:32stefan.richthofersetmessages: + msg11009
2017-01-06 18:05:42stefan.richthofersetassignee: stefan.richthofer
messages: + msg11008
2017-01-06 15:40:09stefan.richthofersetmessages: + msg11007
2016-08-24 20:30:02zyasoftsetresolution: accepted
messages: + msg10909
nosy: + zyasoft
milestone: Jython 2.7.2
2016-08-20 14:26:51stefan.richthofersetpriority: normal
components: + Library
versions: + Jython 2.7
2016-08-20 14:23:14stefan.richthofercreate