-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #43 from Anaconda-Platform/fusion-details
Add registers_fusion_function:true if a notebook contains @fusion.register
- Loading branch information
Showing
10 changed files
with
299 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# -*- coding: utf-8 -*- | ||
# ---------------------------------------------------------------------------- | ||
# Copyright © 2017, Continuum Analytics, Inc. All rights reserved. | ||
# | ||
# The full license is in the file LICENSE.txt, distributed with this software. | ||
# ---------------------------------------------------------------------------- | ||
"""Analyze notebook files.""" | ||
from __future__ import absolute_import | ||
|
||
import codecs | ||
import json | ||
import re | ||
|
||
from anaconda_project.internal.py2_compat import is_string | ||
|
||
_comment_re = re.compile("#.*$", re.MULTILINE) | ||
_fusion_register_re = re.compile(r"^\s*@fusion\.register", re.MULTILINE) | ||
|
||
|
||
# see if some source has @fusion.register. This is | ||
# obviously sort of heuristic, but without executing | ||
# the python we can only do so much. | ||
def _has_fusion_register(source): | ||
# dump comments so commenting out fusion.register | ||
# would work as expected | ||
source = re.sub(_comment_re, "", source) | ||
return re.match(_fusion_register_re, source) is not None | ||
|
||
|
||
def extras(filename, errors): | ||
try: | ||
with codecs.open(filename, encoding='utf-8') as f: | ||
json_string = f.read() | ||
parsed = json.loads(json_string) | ||
except Exception as e: | ||
errors.append("Failed to read or parse %s: %s" % (filename, str(e))) | ||
return None | ||
|
||
extras = dict() | ||
found_fusion = False | ||
|
||
if isinstance(parsed, dict) and \ | ||
'cells' in parsed and \ | ||
isinstance(parsed['cells'], list): | ||
for cell in parsed['cells']: | ||
if 'source' in cell: | ||
if isinstance(cell['source'], list): | ||
source = "".join([s for s in cell['source'] if is_string(s)]) | ||
if _has_fusion_register(source): | ||
found_fusion = True | ||
|
||
if found_fusion: | ||
extras['registers_fusion_function'] = True | ||
|
||
return extras |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
# -*- coding: utf-8 -*- | ||
# ---------------------------------------------------------------------------- | ||
# Copyright © 2017, Continuum Analytics, Inc. All rights reserved. | ||
# | ||
# The full license is in the file LICENSE.txt, distributed with this software. | ||
# ---------------------------------------------------------------------------- | ||
from __future__ import absolute_import, print_function, unicode_literals | ||
|
||
import json | ||
import os | ||
|
||
import anaconda_project.internal.notebook_analyzer as notebook_analyzer | ||
|
||
from anaconda_project.internal.test.tmpfile_utils import with_directory_contents | ||
|
||
|
||
def _fake_notebook_json_with_code(source): | ||
ipynb = { | ||
"cells": [ | ||
{"cell_type": "code", | ||
# source is a list of lines with the newline included in each | ||
"source": [(s + "\n") for s in source.split("\n")]} | ||
] | ||
} | ||
return ipynb | ||
|
||
|
||
def _with_code_in_notebook_file(source, f): | ||
def check(dirname): | ||
filename = os.path.join(dirname, "foo.ipynb") | ||
return f(filename) | ||
|
||
json_string = json.dumps(_fake_notebook_json_with_code(source)) | ||
with_directory_contents({"foo.ipynb": json_string}, check) | ||
|
||
|
||
def test_extras_with_simple_has_fusion_register(): | ||
def check(filename): | ||
errors = [] | ||
extras = notebook_analyzer.extras(filename, errors) | ||
assert [] == errors | ||
assert extras == {'registers_fusion_function': True} | ||
|
||
_with_code_in_notebook_file(""" | ||
@fusion.register | ||
def some_func(): | ||
pass | ||
""", check) | ||
|
||
|
||
def test_extras_without_has_fusion_register(): | ||
def check(filename): | ||
errors = [] | ||
extras = notebook_analyzer.extras(filename, errors) | ||
assert [] == errors | ||
assert extras == {} | ||
|
||
_with_code_in_notebook_file(""" | ||
def some_func(): | ||
pass | ||
""", check) | ||
|
||
|
||
def test_fusion_register(): | ||
assert not notebook_analyzer._has_fusion_register("") | ||
assert not notebook_analyzer._has_fusion_register("fusion.register\n") | ||
assert notebook_analyzer._has_fusion_register("@fusion.register\n") | ||
assert notebook_analyzer._has_fusion_register(" @fusion.register\n") | ||
assert not notebook_analyzer._has_fusion_register("# @fusion.register\n") | ||
assert notebook_analyzer._has_fusion_register("# foo\n@fusion.register\n") | ||
assert notebook_analyzer._has_fusion_register("# foo\n\n @fusion.register\n") | ||
assert notebook_analyzer._has_fusion_register("@fusion.register # foo\n") | ||
assert notebook_analyzer._has_fusion_register(""" | ||
@fusion.register(args=blah) | ||
def some_func(): | ||
pass | ||
""") | ||
assert not notebook_analyzer._has_fusion_register(""" | ||
# @fusion.register | ||
def some_func(): | ||
pass | ||
""") | ||
|
||
|
||
def test_extras_with_io_error(monkeypatch): | ||
def mock_codecs_open(*args, **kwargs): | ||
raise IOError("Nope") | ||
|
||
monkeypatch.setattr('codecs.open', mock_codecs_open) | ||
errors = [] | ||
extras = notebook_analyzer.extras("blah", errors) | ||
assert [] != errors | ||
assert extras is None | ||
assert 'Failed to read or parse' in errors[0] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.