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 related magic functions #1770

Merged
merged 6 commits into from May 31, 2012
Merged

Conversation

ellisonbg
Copy link
Member

This is the first version of Cython related magic functions. An example notebook is provided. I am still finishing the docstrings, but the code should be done.

'-f', '--force', action='store_true', default=False,
help="Force the compilation of the pyx module even if it hasn't changed"
)
@skip_doctest
Copy link
Member

Choose a reason for hiding this comment

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

Why the @skip_doctest? There's no doctest in there, so it's not needed.

@fperez
Copy link
Member

fperez commented May 28, 2012

I haven't gone over it in detail yet, but it's looking great! This is going to be really awesome.

One quick note: I think we should get into the habit of writing a standalone test file for these. There's a clean enough API now to call the cell magics that writing a proper test should be very straightforward, and it will make it much easier to build trust in the system in the long haul, if each extension has a nice little test file along with it.

@ellisonbg
Copy link
Member Author

I am writing tests and running into the fact that these tests require 1) Cython to be installed (I can test for this) and 2) a working compiler. What do you think is the best way of handling the compiler issues?

if not module_name:
raise ValueError('module name must be given')
fname = module_name + '.pyx'
with open(fname, 'w') as f:
Copy link
Member Author

Choose a reason for hiding this comment

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

@takluyver do I need to be more careful about writing the .pyx files for Python 3?

Copy link
Member

Choose a reason for hiding this comment

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

Not just for Python 3, I think - this is liable to break with non-ascii characters on Python 2 as well. I think the best thing is to use io.open(fname, 'w', encoding='utf-8').

Cython, like Python 3, assumes UTF-8 source code by default, so we don't need an encoding cookie: http://docs.cython.org/src/tutorial/strings.html#source-code-encoding

@ellisonbg
Copy link
Member Author

Part of the problem is that I don't have any system w/o a compiler to know how it will fail w/o one.

@fperez
Copy link
Member

fperez commented May 28, 2012

I figure that the tests should just have a skipif (or rather a file-level test flag so nose ignores the whole file) if Cython isn't importable. If cython is present and no compiler, well, let them fail, since that's a pretty borked setup to have :)

@ellisonbg
Copy link
Member Author

OK I already have the file level test for cython, so we should be set.

On Sun, May 27, 2012 at 8:54 PM, Fernando Perez
reply@reply.github.com
wrote:

I figure that the tests should just have a skipif (or rather a file-level test flag so nose ignores the whole file) if Cython isn't importable.  If cython is present and no compiler, well, let them fail, since that's a pretty borked setup to have :)


Reply to this email directly or view it on GitHub:
#1770 (comment)

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

import Cython
except:
pass
else:
Copy link
Member

Choose a reason for hiding this comment

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

Instead of a whole file-level indentation, it would be cleaner to use

try:
  import cython
except:
  __test__ = False

def test()...

That will make nose skip the whole module if cython isn't around, without the ugliness of indenting the whole file.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixec.

Copy link
Member

Choose a reason for hiding this comment

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

I did not know about this, excellent to know!

@ellisonbg
Copy link
Member Author

OK I have added docstrings. I have finished everything that I know of so this could be merged or we can wait for additional review.

@fperez
Copy link
Member

fperez commented May 28, 2012

I'm running test_pr on it now and will report later. In general, it's a good idea to post the test_pr run results with at least 2.7 and 3.2, so we know what both 2.x and 3.x are reasonably covered.

@fperez
Copy link
Member

fperez commented May 28, 2012

Test results for commit d4163c6 merged into master
Platform: linux2

Not available for testing:

@fperez
Copy link
Member

fperez commented May 28, 2012

The log shows the problem: the cythonmagic extension needs to be put into the test machinery with a guard in case the user doesn't have cython installed, so the test suite doesn't blow up on them. Your fixes to the test file are good, the problem is the extension itself. We'll need to have in the main testing code a guard for Cython like we have for every other optional component.

@@ -0,0 +1,178 @@
# -*- coding: utf-8 -*-
"""
Copy link
Member

Choose a reason for hiding this comment

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

The module level docstring should have at least a small summary of what the extension does and the main entry points or useful things it provides.

@fperez
Copy link
Member

fperez commented May 28, 2012

As we add more extensions, I'm realizing we badly need to document them. I know we have no time to go back and fix everything that exists, and the notebook is perfect documentation (though we need to figure out how to include them more clearly in our docs, but that's for another day). So it can be a simple page with just a paragraph and a brief list of the magics, and a sentence that says 'in the directory so and so, a detailed notebook is provided that shows the use of these functions'.

Let's create a new section in the docs, Extensions, and drop a short summary of this one to get the ball rolling. That way it will be easier to update later with short descriptions for the others. It shouldn't take more than a few minutes, and once we solve the problem of linking notebooks in the docs, it will serve as a reference point for people to discover what's available, and then go to the individual notebooks with hands-on explanation.

@minrk
Copy link
Member

minrk commented May 28, 2012

copyright date discussion was in PR #1644

As for notebooks as docs: until we are doing regular sphinx or other export for the notebooks, they have one glaring shortcoming as documentation: they are not searchable. We are adding to documentation, for which none of anyone's standard documentation discovery mechanisms will help.

@fperez
Copy link
Member

fperez commented May 28, 2012

I've been thinking that the fact that we're writing so much as notebooks is pushing up the priority of finishing nbconvert very very high (and integrating it into the doc build). Because you're completely correct: right now the notebook docs we have are a ghetto we know about, but nobody will find on their own unless they go manually exploring a source download (since binary installs don't even have them).

This could be something we could ask on the list to see if anyone has spare cycles to work on: high value and not too hard.

@fperez
Copy link
Member

fperez commented May 29, 2012

This is looking great. As far as I'm concerned, with a bit more docstrings and the isolation issue fixed for the test suite, it can go in.

@ellisonbg
Copy link
Member Author

OK I will try to work on that tonight.

On Tue, May 29, 2012 at 4:38 PM, Fernando Perez
reply@reply.github.com
wrote:

This is looking great.  As far as I'm concerned, with a bit more docstrings and the isolation issue fixed for the test suite, it can go in.


Reply to this email directly or view it on GitHub:
#1770 (comment)

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

"""Compile and import everything from a Cython code cell.

The contents of the cell are written to a `.pyx` file in the
`~/.cython/magic` using a filename with the hash of the code.
Copy link
Contributor

Choose a reason for hiding this comment

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

Cython does not use a ~/.cython directory at the moment, but what about if it did in the future? Maybe we should stay within our namespace by using something like ~/.ipy_cython_magic?

Copy link
Member

Choose a reason for hiding this comment

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

Cython does use ~/.cython directory to store caches of compiled code (e.g. ~/.cython/inline), but perhaps it makes more sense to store this stuff in the profile_dir? I don't think we should be creating any new directories outside IPYTHON_DIR.

Copy link
Contributor

Choose a reason for hiding this comment

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

Well in that case maybe we should use ~/.cython/ipy_magic ? I see that the bulk of the code is just a modified version of Cython.Build.Inline.cython_inline so this makes me feel more comfortable using ~/.cython/magic.

It's too bad Cython or pyximport doesn't expose an API for this sort module building and caching.

Copy link
Member Author

Choose a reason for hiding this comment

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

The reason I went with ~/.cython/magic is that I could imagine that
this extension might someday be maintained and shipped with Cython. I
am fine doing ~/.cython/ipy_magic though as it is more specific.
@minrk are you OK with this or do you really think we should stick
within the profile dir?

On Tue, May 29, 2012 at 7:39 PM, Bradley M. Froehle
reply@reply.github.com
wrote:

  •        else:
  •            module = import_module(module_name)
  •            self._reloads[module_name] = module
  •        self._import_all(module)
    +
  •    @magic_arguments()
  •    @argument(
  •        '-f', '--force', action='store_true', default=False,
  •        help="Force the compilation of the pyx module even if it hasn't changed"
  •    )
  •    @cell_magic
  •    def cython(self, line, cell):
  •        """Compile and import everything from a Cython code cell.
    +
  •        The contents of the cell are written to a .pyx file in the
  •        ~/.cython/magic using a filename with the hash of the code.

Well in that case maybe we should use ~/.cython/ipy_magic ?


Reply to this email directly or view it on GitHub:
https://github.com/ipython/ipython/pull/1770/files#r897576

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

Copy link
Member

Choose a reason for hiding this comment

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

I don't think it's particularly important. It seems a little bit funky to be using another program's private storage dir, so I might lean slightly towards putting it in the profile dir. We could just ping cython-users, and see what they officially recommend for this kind of behavior.

I don't think the idea that this might some day end up in Cython itself should be relevant to where it caches while it resides in IPython, given that it is such an inconsequential thing to change.

I've also always been a bit more partial to 'ipfoo' than 'ipy_foo' for denoting IPython things, so if it's in .cython, I would prefer 'ipmagic' to 'ipy_magic', but I don't feel strongly (or, I do but I know it's silly, so I will pretend that I don't).

pro profile-dir: IPython only writes data to its own dir
pro .cython: all your Cython caches (that I know of) are in ~/.cython, so trashing all Cython caches is a single rm -rf.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for all of this discussion on a relatively trivial point. At this point I'd rank the options as:

  1. ~/.cython/ipmagic (or ~/.cython/ipy_magic)
  2. IPython profile dir
  3. ~/.cython/magic

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, my verbosity tends to be inversely proportional to the actual significance of the issue at hand.

I pinged cython-users, and they recommended IPython's own dir. This could be per-profile, or even top-level IPYTHONDIR/cythonmagic.

@fperez
Copy link
Member

fperez commented May 30, 2012

My vote would be top-level, so we get maximum cache reuse (if two profiles create the same function, there's no harm in benefitting from reusing the cache).

If the cython guys end up later on carrying this, it's easy to move the cache location to be ~/.cython (or whatever they're using at the time), but up until then we should contain our creation of storage areas to IPYTHONDIR.

@minrk
Copy link
Member

minrk commented May 30, 2012

so ipythondir/cython[magic], then?

@fperez
Copy link
Member

fperez commented May 30, 2012

I'm happy without the additional 'magic' there, but don't care too much either way. I'll be OK with either choice, your/Brian's preference.

* File writes are unicode safe.
* Using IPYTHONDIR/cython for code cache.
args = parse_argstring(self.cython, line)
code = cell if cell.endswith('\n') else cell+'\n'
# distutils.Extension cannot handle sources that a unicode
lib_dir=str(os.path.join(self.shell.ipython_dir,'cython'))
Copy link
Member Author

Choose a reason for hiding this comment

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

@takluyver @fperez and @minrk how should I handle the fact that distutils.Extension cannot handle unicode paths? Right now to get it to work I am just calling str on this path.

Copy link
Member

Choose a reason for hiding this comment

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

How about calling X.encode(encoding), with encoding='utf-16' on windows and utf-8 elsewhere? If we can believe this post, Windows uses utf-16 uniformly for filesystem encoding, so that should work.

Copy link
Member

Choose a reason for hiding this comment

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

Here's a Stack overflow post confirming the above, so that should be a good approach.

Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't it be sys.getfilesystemencoding()?

Also, we should be careful that it is str, not bytes, since presumably py3 distutils isn't this broken.

This is a stupid bug in distutils - I commented out the type checking in distutils, and the inlining with unicode paths works perfectly. Unfortunately, I don't see a clean way of monkeypatching to just fix the checks.

Copy link
Member Author

Choose a reason for hiding this comment

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

Can you check to see what py3 distutils expects here?

On Wed, May 30, 2012 at 8:37 PM, Min RK
reply@reply.github.com
wrote:

  •        The contents of the cell are written to a .pyx file in the
  •        directory IPYTHONDIR/cython using a filename with the hash of the code.
  •        This file is then cythonized and compiled. The resulting module
  •        is imported and all of its symbols are injected into the user's
  •        namespace. The usage is similar to that of %%cython_pyximport but
  •        you don't have to pass a module name::
    +
  •        %%cython
  •        def f(x):
  •            return 2.0*x
  •        """
  •        args = parse_argstring(self.cython, line)
  •        code = cell if cell.endswith('\n') else cell+'\n'
  •        # distutils.Extension cannot handle sources that a unicode
  •        lib_dir=str(os.path.join(self.shell.ipython_dir,'cython'))

Shouldn't it be sys.getfilesystemencoding()?

Also, we should be careful that it is str, not bytes, since presumably py3 distutils isn't this broken.

This is a stupid bug in distutils - I commented out the type checking in distutils, and the inlining with unicode paths works perfectly.  Unfortunately, I don't see a clean way of monkeypatching to just fix the checks.


Reply to this email directly or view it on GitHub:
https://github.com/ipython/ipython/pull/1770/files#r905304

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

Copy link
Member

Choose a reason for hiding this comment

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

OK, done.

Copy link
Member

Choose a reason for hiding this comment

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

Great, thanks!

Copy link
Member Author

Choose a reason for hiding this comment

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

But wait , it has to be str, not bytes

Sent from my iPad

On May 31, 2012, at 8:08 AM, Fernando Perezreply@reply.github.com wrote:

  •    The contents of the cell are written to a `.pyx` file in the
    
  •    directory `IPYTHONDIR/cython` using a filename with the hash of the code.
    
  •    This file is then cythonized and compiled. The resulting module
    
  •    is imported and all of its symbols are injected into the user's
    
  •    namespace. The usage is similar to that of `%%cython_pyximport` but
    
  •    you don't have to pass a module name::
    
  •    %%cython
    
  •    def f(x):
    
  •        return 2.0*x
    
  •    """
    
  •    args = parse_argstring(self.cython, line)
    
  •    code = cell if cell.endswith('\n') else cell+'\n'
    
  •    # distutils.Extension cannot handle sources that a unicode
    
  •    lib_dir=str(os.path.join(self.shell.ipython_dir,'cython'))
    

@takluyver, thanks! We actually looked at the py3compat utilities, but since we don't know them too well, we didn't quite pick the right approach. Why don't you just go ahead and apply this fix straight up into master? Things like that are OK in my mind to do post-review without needing the overhead of a full-blown PR, they're just minor polish that would have happened during review with a bit more time.


Reply to this email directly or view it on GitHub:
https://github.com/ipython/ipython/pull/1770/files#r908331

Copy link
Member

Choose a reason for hiding this comment

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

cast_bytes_py2 casts to bytes (which is the same as str) on Python 2, and doesn't do anything on Python 3.

Copy link
Member Author

Choose a reason for hiding this comment

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

OK sounds good.

On Thu, May 31, 2012 at 12:40 PM, Thomas Kluyver
reply@reply.github.com
wrote:

  •        The contents of the cell are written to a .pyx file in the
  •        directory IPYTHONDIR/cython using a filename with the hash of the code.
  •        This file is then cythonized and compiled. The resulting module
  •        is imported and all of its symbols are injected into the user's
  •        namespace. The usage is similar to that of %%cython_pyximport but
  •        you don't have to pass a module name::
    +
  •        %%cython
  •        def f(x):
  •            return 2.0*x
  •        """
  •        args = parse_argstring(self.cython, line)
  •        code = cell if cell.endswith('\n') else cell+'\n'
  •        # distutils.Extension cannot handle sources that a unicode
  •        lib_dir=str(os.path.join(self.shell.ipython_dir,'cython'))

cast_bytes_py2 casts to bytes (which is the same as str) on Python 2, and doesn't do anything on Python 3.


Reply to this email directly or view it on GitHub:
https://github.com/ipython/ipython/pull/1770/files#r910556

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

* Added extension to the Sphinx docs.
* Fixed unicode issues.
@ellisonbg
Copy link
Member Author

@fperez: OK I think I have done everything. If all passes on py3, it is ready to merge.

One other point: I can't build the docs on OS X. I get the following error:

ValueError: Could not import class or module 'IPython.core.magics' specified for inheritance diagram

@fperez
Copy link
Member

fperez commented May 31, 2012

On Wed, May 30, 2012 at 10:04 PM, Brian E. Granger
reply@reply.github.com
wrote:

@fperez: OK I think I have done everything.  If all passes on py3, it is ready to merge.

Running the tests now...

One other point: I can't build the docs on OS X.  I get the following error:

ValueError: Could not import class or module 'IPython.core.magics' specified for inheritance diagram

Mmh, that's odd. Let me rerun here, though I'm pretty sure they did
work because I uploaded a new build when we merged the big magics
branch. Just to be safe, did you rerun make clean first? Sometimes
stale sphinx stuff can break a build.

@ellisonbg
Copy link
Member Author

Yep I did a make clean first.

On Wed, May 30, 2012 at 10:09 PM, Fernando Perez
reply@reply.github.com
wrote:

On Wed, May 30, 2012 at 10:04 PM, Brian E. Granger
reply@reply.github.com
wrote:

@fperez: OK I think I have done everything.  If all passes on py3, it is ready to merge.

Running the tests now...

One other point: I can't build the docs on OS X.  I get the following error:

ValueError: Could not import class or module 'IPython.core.magics' specified for inheritance diagram

Mmh, that's odd.  Let me rerun here, though I'm pretty sure they did
work because I uploaded a new build when we merged the big magics
branch.  Just to be safe, did you rerun make clean first?  Sometimes
stale sphinx stuff can break a build.


Reply to this email directly or view it on GitHub:
#1770 (comment)

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

@fperez
Copy link
Member

fperez commented May 31, 2012

Test results for commit c80e366 merged into master
Platform: linux2

Not available for testing:

@fperez
Copy link
Member

fperez commented May 31, 2012

Mmh, ignore that py3 failure, I have no idea why test_pr is picking up a 2.x matplotlib! @takluyver, I would have thought your recent PYTHONPATH fixes to test_pr would take care of that. Does this failure make sense to you?

@ellisonbg
Copy link
Member Author

So the test failure looks like it is related to the 2.7 version of matplotlib being used in python 3. Yes, as you were saying...

@fperez
Copy link
Member

fperez commented May 31, 2012

OK, I'm merging this: we have no major problems left, and at this point more work here hits diminishing returns, IMO. We can always polish further in master. Brian, great job, thanks!!

@ellisonbg
Copy link
Member Author

Yipee, cython!

On Wed, May 30, 2012 at 10:16 PM, Fernando Perez
reply@reply.github.com
wrote:

OK, I'm merging this: we have no major problems left, and at this point more work here hits diminishing returns, IMO.  We can always polish further in master.  Brian, great job, thanks!!


Reply to this email directly or view it on GitHub:
#1770 (comment)

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

fperez added a commit that referenced this pull request May 31, 2012
Cython related magic functions: offers the new cell magics %%cython_inline, %%cython_pyximport and %%cython to make it very easy to put cython-accelerated code in a cell and have it loaded interactively.
@fperez fperez merged commit 42f1e81 into ipython:master May 31, 2012
mattvonrocketstein pushed a commit to mattvonrocketstein/ipython that referenced this pull request Nov 3, 2014
Cython related magic functions: offers the new cell magics %%cython_inline, %%cython_pyximport and %%cython to make it very easy to put cython-accelerated code in a cell and have it loaded interactively.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants