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

nbconvert: Make sure node is atleast version 0.9.12 #5279

Merged
merged 5 commits into from Mar 5, 2014

Conversation

jdfreder
Copy link
Member

@jdfreder jdfreder commented Mar 5, 2014

Trying to export html using nbconvert and an older version of node fails silently. All of the markdown gets stripped from the document. I used nvm to install and test node.js with our marked.js for node versions 0.6+. I discovered only node versions 0.9.12 and up produce any output. 0.8 and earlier produce no output and 0.9.11 and earlier hang.

This PR adds a test that makes sure that node is the right version before deciding to use it, otherwise pandoc is used.
#5263

else:
# Remove the version 'v' prefix from the output and strip whitespace.
version_str = getoutput(cmd + ' --version').replace('v', '').strip()
try:
Copy link
Member

Choose a reason for hiding this comment

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

See IPython.utils.version.check_version

Copy link
Member

Choose a reason for hiding this comment

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

This whole block can just be:

try:
    out, err, rc = get_output_error_code([cmd, '--version'])
except OSError:
    # command not found
    return False
if rc:
    # command failed
    return False
return check_version(out.lstrip('v'), '0.9.12')

@jdfreder
Copy link
Member Author

jdfreder commented Mar 5, 2014

@minrk I love the check_version function. I made the changes and pushed, what do you think of having the return_code on the same line as the check_version call (see checked in code).

@minrk
Copy link
Member

minrk commented Mar 5, 2014

what do you think of having the return_code on the same line as the check_version call (see checked in code).

Not what I would have done, but it's fine.

@minrk
Copy link
Member

minrk commented Mar 5, 2014

I realize there is one more thing missing in this fallback. In the case of neither node nor pandoc being present, the user will be presented with a 'pandoc missing' error, rather than recommending the preferred installation of 'node' for HTML conversion. I'm not certain we should address that in this PR, but it is suboptimal.

@takluyver
Copy link
Member

It's not ideal that this is running subprocesses on import, either. But it was doing that before this change, so it's not critical to fix now.

@minrk
Copy link
Member

minrk commented Mar 5, 2014

I think we can merge this one. Maybe I'll take a pass at cleaning up both node and pandoc checking later if it keeps bothering me.

@minrk
Copy link
Member

minrk commented Mar 5, 2014

But it was doing that before

It was not launching node before, just locating it (which may have involved calling which).

@jdfreder
Copy link
Member Author

jdfreder commented Mar 5, 2014

I can add a warning to the else where node isn't found... something like

warnings.warn(  "Node.js 0.9.12 or later wasn't found.\n" +
                                "Nbconvert will try to use Pandoc instead.")

Also I can move the logic into a method that runs once and caches the results- so subprocess isn't called on import.

@minrk
Copy link
Member

minrk commented Mar 5, 2014

I can add a warning to the else where node isn't found

No, what we absolutely must not do is add a warning on import.

@jdfreder
Copy link
Member Author

jdfreder commented Mar 5, 2014

must not do is add a warning on import.

Is that a no to moving it into a method that runs once when the code is called too?

I was thinking

def markdown2html(source):
    """Convert a markdown string to HTML"""
    if _node[0] is None:
        # prefer md2html via marked if node.js >= 0.9.12 is available
        # node is called nodejs on debian, so try that first
        node_cmd = 'nodejs'
        if _verify_node(node_cmd):
            _node[0] = True
        else:
            node_cmd = 'node'
            if _verify_node(node_cmd):
                _node[0] = True
            else:
                warnings.warn(  "Node.js 0.9.12 or later wasn't found.\n" +
                                "Nbconvert will try to use Pandoc instead.")
                _node[0] = False
    if not _node[0]:
        return markdown2html_pandoc(source)
    else:
        return markdown2html_marked(source)

Pardon the [0] - scope issues.

@jdfreder
Copy link
Member Author

jdfreder commented Mar 5, 2014

Actually like this:

def markdown2html(source):
    """Convert a markdown string to HTML"""
    if _node[0] is None:
        # prefer md2html via marked if node.js >= 0.9.12 is available
        # node is called nodejs on debian, so try that first
        _node[0] = 'nodejs'
        if not _verify_node(_node[0] ):
            _node[0] = 'node'
            if not _verify_node(_node[0] ):
                warnings.warn(  "Node.js 0.9.12 or later wasn't found.\n" +
                                "Nbconvert will try to use Pandoc instead.")
                _node[0] = False
    if not _node[0]:
        return markdown2html_pandoc(source)
    else:
        return markdown2html_marked(source)

@minrk
Copy link
Member

minrk commented Mar 5, 2014

Something like that should be fine. Except for the _node[0] index access. Why would you do that?

@jdfreder
Copy link
Member Author

jdfreder commented Mar 5, 2014

. Why would you do that?

Because the method isn't child to a class, so I don't have a self to store the results in (variable assignment). I could do global _node instead, but I thought globals were generally a bad idea, right? Also I think the new local keyword is Python 3 only right?

@jdfreder
Copy link
Member Author

jdfreder commented Mar 5, 2014

... or we could just not cache the results, and run the check each time

@minrk
Copy link
Member

minrk commented Mar 5, 2014

_node is already a global. There is no benefit to making it a global container with one element rather than a singleton.

@jdfreder
Copy link
Member Author

jdfreder commented Mar 5, 2014

_node is already a global. There is no benefit to making it a global container with one element rather than a singleton.

Ahh okay, I was totally confused about the scope of global then. I thought it spanned across imports, but you're saying it only will span across imports if it is explicitly imported (i.e. from markdown import _node)?

@minrk
Copy link
Member

minrk commented Mar 5, 2014

global just means module-level

@jdfreder
Copy link
Member Author

jdfreder commented Mar 5, 2014

@takluyver and @minrk want to take a look again? I moved the code into a method and added a warning for the no-node case.

warnings.warn( "Node.js 0.9.12 or later wasn't found.\n" +
"Nbconvert will try to use Pandoc instead.")
_node = False
if not _node:
Copy link
Member

Choose a reason for hiding this comment

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

Why not switch the if/else round and do if _node instead of if not _node?

Copy link
Member

Choose a reason for hiding this comment

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

+1 to switching this one around, otherwise ready to merge, I think.

Copy link
Member Author

Choose a reason for hiding this comment

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

Wasn't sure if there was ever a case where CBool(string) could == False... I guess I was just being overly cautious. Does that bother you? I can rotate them.

Copy link
Member

Choose a reason for hiding this comment

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

An empty string booleates to False, but it would work the same whether you test s or not s.

@takluyver
Copy link
Member

Yes, this no longer executes a subcommand on import. 👍

@minrk
Copy link
Member

minrk commented Mar 5, 2014

Great, this looks good to me now. Thanks, @jdfreder.

@jdfreder
Copy link
Member Author

jdfreder commented Mar 5, 2014

Order switched

takluyver added a commit that referenced this pull request Mar 5, 2014
nbconvert: Make sure node is atleast version 0.9.12
@takluyver takluyver merged commit 19e95e0 into ipython:master Mar 5, 2014
@jdfreder jdfreder deleted the checknode branch March 5, 2014 23:16
mattvonrocketstein pushed a commit to mattvonrocketstein/ipython that referenced this pull request Nov 3, 2014
nbconvert: Make sure node is atleast version 0.9.12
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

3 participants