Skip to content
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

Cython: embed signatures in docstrings of Sage library code #17847

Closed
jdemeyer opened this issue Feb 24, 2015 · 137 comments
Closed

Cython: embed signatures in docstrings of Sage library code #17847

jdemeyer opened this issue Feb 24, 2015 · 137 comments

Comments

@jdemeyer
Copy link

Before:

sage: print GF(5).factored_unit_order.__doc__
File: sage/rings/finite_rings/finite_field_base.pyx (starting at line 729)

        Returns the factorization of ``self.order()-1``, as a 1-element list.

        The format is for compatibility with
        :mod:`~sage.rings.finite_rings.integer_mod_ring`.

        EXAMPLES::

            sage: GF(7^2,'a').factored_unit_order()
            [2^4 * 3]
        

After:

sage: print GF(5).factored_unit_order.__doc__
FiniteField.factored_unit_order(self)
File: sage/rings/finite_rings/finite_field_base.pyx (starting at line 729)

        Returns the factorization of ``self.order()-1``, as a 1-element list.

        The format is for compatibility with
        :mod:`~sage.rings.finite_rings.integer_mod_ring`.

        EXAMPLES::

            sage: GF(7^2,'a').factored_unit_order()
            [2^4 * 3]
        

Upstream bug which will be fixed in Cython 0.23:

Upstream: Fixed upstream, but not in a stable release.

CC: @simon-king-jena

Component: cython

Author: Jeroen Demeyer, Simon King

Branch/Commit: cc9e9f6

Reviewer: Simon King, Jeroen Demeyer

Issue created by migration from https://trac.sagemath.org/ticket/17847

@jdemeyer jdemeyer added this to the sage-6.6 milestone Feb 24, 2015
@jdemeyer

This comment has been minimized.

@jdemeyer

This comment has been minimized.

@jdemeyer
Copy link
Author

Upstream: Reported upstream. No feedback yet.

@jdemeyer

This comment has been minimized.

@jdemeyer

This comment has been minimized.

@jdemeyer
Copy link
Author

Branch: u/jdemeyer/ticket/17847

@jdemeyer
Copy link
Author

Changed branch from u/jdemeyer/ticket/17847 to none

@jdemeyer
Copy link
Author

comment:6

The attached branch mostly works, but there are still issues in src/sage/misc/sageinspect.py

In particular, I need help with navigating this maze:

def _sage_getsourcelines_name_with_dot(object):
    r"""
    [...]
    AUTHOR:

    - Simon King (2011-09)
    """
    # First, split the name:
    if '.' in object.__name__:
        splitted_name = object.__name__.split('.')
    elif hasattr(object,'__qualname__'):
        splitted_name = object.__qualname__.split('.')
    else:
        splitted_name = object.__name__
    path = object.__module__.split('.')+splitted_name[:-1]
    name = splitted_name[-1]
    try:
        M = __import__(path.pop(0))
    except ImportError:
        try:
            B = object.__base__
            if B is None:
                raise AttributeError
        except AttributeError:
            raise IOError("could not get source code")
        return sage_getsourcelines(B)
    # M should just be the top-most module.
    # Hence, normally it is just 'sage'
    try:
        while path:
            M = getattr(M, path.pop(0))
    except AttributeError:
        try:
            B = object.__base__
            if B is None:
                raise AttributeError
        except AttributeError:
            raise IOError("could not get source code")
        return sage_getsourcelines(B)

    lines, base_lineno = sage_getsourcelines(M)
    [...]

@jdemeyer
Copy link
Author

Branch: u/jdemeyer/ticket/17847

@jdemeyer
Copy link
Author

New commits:

6d2b63aCython: embed signatures in docstrings

@jdemeyer
Copy link
Author

Commit: 6d2b63a

@simon-king-jena
Copy link
Member

comment:9

Replying to @jdemeyer:

The attached branch mostly works, but there are still issues in src/sage/misc/sageinspect.py

In particular, I need help with navigating this maze:

def _sage_getsourcelines_name_with_dot(object):

That's for dynamic classes, hence, it is pure Python, and the embedding in docstrings isn't relevant here.

Details: In the category framework we have all these nested dynamic classes which get a name that is formed by the name of a class they will be attribute of. Hence:

class Modules(Category):
    def __init__(...):
        ...
    class Homset(Homset_generic):
        def __init__(...)

Hence, you have a class Modules and you have an attribute Modules.Homset that itself is a class (nested classes). Now, you will find:

sage: Modules.Homset.__name__
'Modules.Homset'

Hence, you will NOT find the source code of the class by searching the name in the source file. But the name does give you a possibility to find the code, namely by first searching for the source of the class Modules in the source file and then searching for the source of the class Homset in the source of Modules.

It isn't relevant for Cython classes, since there is a metaclass at work (and you can't have metaclass for Cython classes). It could perhaps be in a cython file, though.

@jdemeyer
Copy link
Author

Dependencies: #17851

@jdemeyer

This comment has been minimized.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Feb 25, 2015

Branch pushed to git repo; I updated commit sha1. New commits:

98a5813Nuke Cython cache when Cython version changes
9cd65e1Merge commit '98a581300ec495b9c39ebe3484f407a491f8bb95' into t/17847/ticket/17847

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Feb 25, 2015

Changed commit from 6d2b63a to 9cd65e1

@jdemeyer
Copy link
Author

comment:13

Replying to @simon-king-jena:

Replying to @jdemeyer:

The attached branch mostly works, but there are still issues in src/sage/misc/sageinspect.py

In particular, I need help with navigating this maze:

def _sage_getsourcelines_name_with_dot(object):

That's for dynamic classes, hence, it is pure Python, and the embedding in docstrings isn't relevant here.

Apparently it is relevant, since I'm getting doctest failures in this function:

sage -t src/sage/misc/nested_class_test.py
**********************************************************************
File "src/sage/misc/nested_class_test.py", line 215, in sage.misc.nested_class_test.TestNestedParent
Failed example:
    print sage_getsource(E)
Exception raised:
    Traceback (most recent call last):
      File "/usr/local/src/sage-git/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 488, in _run
        self.compile_and_execute(example, compiler, test.globs)
      File "/usr/local/src/sage-git/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 850, in compile_and_execute
        exec(compiled, globs)
      File "<doctest sage.misc.nested_class_test.TestNestedParent[5]>", line 1, in <module>
        print sage_getsource(E)
      File "/usr/local/src/sage-git/local/lib/python2.7/site-packages/sage/misc/sageinspect.py", line 1641, in sage_getsource
        t = sage_getsourcelines(obj, is_binary)
      File "/usr/local/src/sage-git/local/lib/python2.7/site-packages/sage/misc/sageinspect.py", line 1895, in sage_getsourcelines
        return obj._sage_src_lines_()
      File "/usr/local/src/sage-git/local/lib/python2.7/site-packages/sage/structure/dynamic_class.py", line 392, in _sage_src_lines
        return sage_getsourcelines(doccls)
      File "/usr/local/src/sage-git/local/lib/python2.7/site-packages/sage/misc/sageinspect.py", line 1921, in sage_getsourcelines
        return _sage_getsourcelines_name_with_dot(obj)
      File "/usr/local/src/sage-git/local/lib/python2.7/site-packages/sage/misc/sageinspect.py", line 1755, in _sage_getsourcelines_name_with_dot
        raise IOError('could not find class definition')
    IOError: could not find class definition
**********************************************************************

@jdemeyer
Copy link
Author

comment:14

The TestNestedParent does inherit from the Cython class Parent, perhaps that's how Cython comes in.

@jdemeyer

This comment has been minimized.

@jdemeyer
Copy link
Author

jdemeyer commented Apr 7, 2015

Changed upstream from Reported upstream. No feedback yet. to Fixed upstream, but not in a stable release.

@jdemeyer
Copy link
Author

jdemeyer commented Apr 7, 2015

Changed dependencies from #17851 to none

@jdemeyer
Copy link
Author

jdemeyer commented Apr 7, 2015

Author: Jeroen Demeyer

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Apr 7, 2015

Changed commit from 9cd65e1 to 1a36cc9

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Apr 7, 2015

Branch pushed to git repo; I updated commit sha1. This was a forced push. New commits:

1a36cc9Cython: embed signatures in docstrings

@jdemeyer
Copy link
Author

jdemeyer commented Apr 7, 2015

comment:18

Rebased and included upstream Cython patch, but it still doesn't work due to the issue with _sage_getsourcelines_name_with_dot()

@simon-king-jena
Copy link
Member

comment:19

OK, I'll have a look.

Do I need to do "sage -ba" to build it, or is that done automatically because of dependency checking?

Best regards,
Simon

@jdemeyer
Copy link
Author

jdemeyer commented Apr 9, 2015

comment:96

I couldn't find any difference in behaviour between foo? or foo?? with or without this patch.

@jdemeyer
Copy link
Author

jdemeyer commented Apr 9, 2015

comment:97

What is this for?

getattr(init, 'im_class', None) == typ

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Apr 9, 2015

Changed commit from 51aa68c to 02ee3cc

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Apr 9, 2015

Branch pushed to git repo; I updated commit sha1. New commits:

02ee3ccFix raise syntax

@simon-king-jena
Copy link
Member

comment:99

Replying to @sagetrac-git:

Branch pushed to git repo; I updated commit sha1. New commits:

02ee3ccFix raise syntax

Thanks, I thought that except (TypeError, AttributeError), err assigns the caught error to err.

@simon-king-jena
Copy link
Member

comment:100

Replying to @jdemeyer:

What is this for?

getattr(init, 'im_class', None) == typ

I wanted to test that the init method belongs to typ and is not inherited from a super class.

But on second thought, it would perhaps be better to work with inheritance: After all, docstrings are inherited, too.

@simon-king-jena
Copy link
Member

comment:101

Replying to @simon-king-jena:

I wanted to test that the init method belongs to typ and is not inherited from a super class.

The original rationale was this: The init method may contain embedding information for the class. If it is obtained from the super-class, then the embedding information belongs to a different class and is thus misleading.

@jdemeyer
Copy link
Author

jdemeyer commented Apr 9, 2015

comment:102

Replying to @simon-king-jena:

But on second thought, it would perhaps be better to work with inheritance: After all, docstrings are inherited, too.

I don't think this should be changed.
I would not like to see the doc of Parent just because esomething something inherits from Parent.

@jdemeyer
Copy link
Author

jdemeyer commented Apr 9, 2015

comment:103

For me, this branch is good to go if you add some comment in the sources about this part:

            if (getattr(init, '__objclass__', None) or
                getattr(init, 'im_class', None)) == typ:
                return sage_getdoc_original(init)

@simon-king-jena
Copy link
Member

comment:104

Replying to @jdemeyer:

For me, this branch is good to go if you add some comment in the sources about this part:

            if (getattr(init, '__objclass__', None) or
                getattr(init, 'im_class', None)) == typ:
                return sage_getdoc_original(init)

I will do so a bit later, as I have an appointment now.

@jdemeyer
Copy link
Author

jdemeyer commented Apr 9, 2015

comment:105

Hmm, this patch doesn't behave so nicely for some of Python's docs:

sage: print type.__doc__
type(object) -> the object's type
type(name, bases, dict) -> a new type

sage: print sage_getdoc_original(type)
type(name, bases, dict) -> a new type

This causes

sage -t --long src/sage/repl/ipython_tests.py
**********************************************************************
File "src/sage/repl/ipython_tests.py", line 10, in sage.repl.ipython_tests
Failed example:
    shell.run_cell(u'%pinfo dummy')
Expected:
    Type:            function
    String form:     <function dummy at 0x...>
    File:            /.../sage/repl/ipython_tests.py
    Definition:      dummy(argument, optional=None)
    Docstring:
       Dummy Docstring Title
    <BLANKLINE>
       Dummy docstring explanation.
    <BLANKLINE>
       INPUT:
    <BLANKLINE>
       * "argument" -- anything. Dummy argument.
    <BLANKLINE>
       * "optional" -- anything (optional). Dummy optional.
    <BLANKLINE>
       EXAMPLES:
    ...
    Class docstring:
    function(code, globals[, name[, argdefs[, closure]]])
    <BLANKLINE>
    Create a function object from a code object and a dictionary. The
    optional name string overrides the name from the code object. The
    optional argdefs tuple specifies the default argument values. The
    optional closure tuple supplies the bindings for free variables.
    Init docstring:  x.__init__(...) initializes x; see help(type(x)) for signature
Got:
    Type:            function
    String form:     <function dummy at 0x7f8a0ffe76e0>
    File:            /usr/local/src/sage-git/local/lib/python2.7/site-packages/sage/repl/ipython_tests.py
    Definition:      dummy(argument, optional=None)
    Docstring:
       Dummy Docstring Title
    <BLANKLINE>
       Dummy docstring explanation.
    <BLANKLINE>
       INPUT:
    <BLANKLINE>
       * "argument" -- anything. Dummy argument.
    <BLANKLINE>
       * "optional" -- anything (optional). Dummy optional.
    <BLANKLINE>
       EXAMPLES:
    <BLANKLINE>
          sage: from sage.repl.ipython_tests import dummy sage: dummy(1)
          'Source code would be here'
    <BLANKLINE>
    Class docstring:
    Create a function object from a code object and a dictionary. The
    optional name string overrides the name from the code object. The
    optional argdefs tuple specifies the default argument values. The
    optional closure tuple supplies the bindings for free variables.
    Init docstring:  x.__init__(...) initializes x; see help(type(x)) for signature
**********************************************************************

@simon-king-jena
Copy link
Member

comment:106

Replying to @jdemeyer:

Hmm, this patch doesn't behave so nicely for some of Python's docs:

sage: print sage_getdoc_original(type)
type(name, bases, dict) -> a new type

Yes. That's because of my attempt to remove the signature. After all, what I have is only a heuristics.

How could we improve the heuristics? Special-case type? Test whether the first line ends with ')'?

I'll finish a commit now. Please wait.

@simon-king-jena
Copy link
Member

Changed branch from u/jdemeyer/ticket/17847 to u/SimonKing/ticket/17847

@simon-king-jena
Copy link
Member

Changed branch from u/SimonKing/ticket/17847 to u/jdemeyer/ticket/17847

@simon-king-jena
Copy link
Member

Changed branch from u/jdemeyer/ticket/17847 to u/SimonKing/ticket/17847

@simon-king-jena
Copy link
Member

comment:109

Why has the branch that I just pushed be reverted???


New commits:

934490aAdd a comment; improve heuristics to strip the embedded signature

@simon-king-jena
Copy link
Member

Changed commit from 02ee3cc to 934490a

@simon-king-jena
Copy link
Member

comment:110

Now it should be ready for review.

@jdemeyer
Copy link
Author

Changed branch from u/SimonKing/ticket/17847 to u/jdemeyer/ticket/17847

@simon-king-jena
Copy link
Member

comment:112

Sorry that I didn't fix that doctest.


New commits:

cc9e9f6Fix IPython doctest

@simon-king-jena
Copy link
Member

Changed commit from 934490a to cc9e9f6

@vbraun
Copy link
Member

vbraun commented Apr 14, 2015

Changed branch from u/jdemeyer/ticket/17847 to cc9e9f6

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

No branches or pull requests

3 participants