Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

ipynb -> ipynb transformer #3747

Closed
wants to merge 24 commits into from

7 participants

@Carreau
Owner

That's basically split Exporter in 2 class, no more, no less. Exporter now call sometime BaseExpoter.super().same_method()

Exporter Also renamed to TemplateExporter

@ivanov
Owner

AttributeError: 'module' object has no attribute 'nbconvert' according to Travis

@wolever

Patch to fix this:

diff --git a/IPython/nbconvert/exporters/exporter.py b/IPython/nbconvert/exporters/exporter.py
index 244b6de..8f2035a 100755
--- a/IPython/nbconvert/exporters/exporter.py
+++ b/IPython/nbconvert/exporters/exporter.py
@@ -40,7 +40,7 @@
 from IPython.nbconvert import filters


-from IPython.nbconvert.exporter.baseexporter import BaseExporter, ResourcesDict
+from .baseexporter import BaseExporter, ResourcesDict

 #-----------------------------------------------------------------------------
 # Globals and constants
@JanSchulz

Could this transformer be used to implement a "remove output before commit"-hook for git? See ipython/nbconvert#142 for the usecase...

@Carreau
Owner
@Carreau
Owner

Rebased and cleaned. (actually redone from scratch).
Some config might be changed form Exporter.foo= to BaseExporter.foo= but this is unnecessary.

I'm wondering if we shouldn't have a dummy IPynb2IPynbExporter class that inherit from BaseExporter just in case we want custom logic later.

Ping @jdfreder

@jdfreder
Owner

Ahh I was waiting for this :smile:
I'll take a look right now

@jdfreder
Owner

It looks good, I have a couple of comments.

  • Right now one can't use the baseexporter from the CLI Do we want to add this functionality now? I personally think this would be great addition (perfect example is the cherry picker plugin I wrote). Maybe an alias like --to notebook. To do so a matching entry would need to be added to exporter.py in the exporter_map.
  • Also, it would be nice if the FilesWriter knew how to write a notebook node object if it recieved it as input. If not maybe a NotebookFilesWriter that inherits from FilesWriter. I prefer the FilesWriter knowing how to write a notebook node object (see small diagram below).

I'm wondering if we shouldn't have a dummy IPynb2IPynbExporter class that inherit from BaseExporter just in case we want custom logic later.

I think I would wait to do that. Most of the logic used in the baseexporter applies to any type of conversion. Since we still need to write some importing stuff, maybe we could do something like this:

(sorry this is so crappy, I drew it in MS Paint)
diagram

@minrk
Owner

naming question: should the base be Exporter and the current Exporter be TemplateExporter? Seems more precisely descriptive to me.

@jdfreder
Owner

Exporter and the current Exporter be TemplateExporter? Seems more precisely descriptive to me.

Agreed

@Carreau
Owner

Right now one can't use the baseexporter from the CLI Do we want to add this functionality now? I personally think this would be great addition (perfect example is the cherry picker plugin I wrote). Maybe an alias like --to notebook. To do so a matching entry would need to be added to exporter.py in the exporter_map.

I think we have 5 month, we better have to wait for BaseExporter to be done before jumping into writing something we will have to do from scratch.

Also, it would be nice if the FilesWriter knew how to write a notebook node object if it recieved it as input. If not maybe a NotebookFilesWriter that inherits from FilesWriter. I prefer the FilesWriter knowing how to write a notebook node object (see small diagram below).

Read and write of .ipynb should use nbformat, which already know how to write .ipynb. I also want NbValidator to be used along the way.

I think I would wait to do that. Most of the logic used in the baseexporter applies to any type of conversion. Since we still need to write some importing stuff, maybe we could do something like this:

Not completely sure about that, I don't quite see what rst2ipynb will reuse in base exporter..

naming question: should the base be Exporter and the current Exporter be TemplateExporter? Seems more precisely descriptive to me.

Ask @ellisonbg he asked @jdfreder to remove the Template suffix.

@jdfreder
Owner

Ask @ellisonbg he asked @jdfreder to remove the Template suffix.

I think that was only in the context of export to something other than a notebook.

Read and write of .ipynb should use nbformat,

Agreed, I was think of adding a check to FilesWriter to check the input. Something like this maybe:

    from IPython.nbformat import current as nbformat

And in the write method:

            # Write conversion results.
            if isinstance(output, NotebookNode):
                self.log.info("Writing notebook to %s", dest)
                with io.open(dest, 'w', encoding='utf-8') as f:
                    nbformat.write(output, fp=f, format='ipynb')
            else:
                self.log.info("Writing %i bytes to %s", len(output), dest)
                with io.open(dest, 'w', encoding='utf-8') as f:
                    f.write(output)
            return dest

writing something we will have to do from scratch.

I'm confused, I was just suggesting adding an entry to export.py, not doing the all the import stuff now, putting that off for later work.

I don't quite see what rst2ipynb will reuse in base exporter..

I think just from_file and from_filename method signatures (not the code inside the methods).

@Carreau
Owner

And rebased again.

@jdfreder
Owner

Other than that, it looks good to me. This should get merged so it doesn't need to be rebased again. @Carreau if you rebase this again, I'll merge it within 24 hrs if there is no objection.

I still think it would be useful to tell the FilesWriter and StdoutWriter how to handle nbnode as input, because without that this is only useful through the API (you can't access the data through the CLI).

@Carreau
Owner
@jdfreder
Owner

Ok

@jdfreder
Owner

Ok, it's rebased in #4175 , closing

@jdfreder jdfreder closed this
minrk and others added some commits
@minrk minrk always fire LOCAL_IPS.extend(PUBLIC_IPS)
was in `else`, but should have been `finally` so it aways runs.


Symptom was warnings in parallel.client about `127.0.1.1` not being this machine.
86434a8
@minrk minrk update version-check message in setup.py and IPython.__init__
clearer message that IPython no longer supports 2.6.
1bca05e
@minrk minrk update Python version classifiers:
- drop specific 3.x
- drop 2.6
e128d4e
@minrk minrk update README with dropped 2.6 and 3.2 support
also clarify the checkout steps in development install
e9a19b0
@takluyver takluyver Use Instance trait for user_ns instead of Dict.
Instance(dict) is None by default, unlike Dict().
f954561
@takluyver takluyver Add a test for kernel started without user_ns kwarg.
user_module should not be an instance of DummyMod
4d6e0e5
@ivanov ivanov Merge pull request #4189 from minrk/localinterfaces-finally
always fire LOCAL_IPS.extend(PUBLIC_IPS)
3ce4b25
@minrk minrk Merge pull request #4188 from takluyver/dict-traitlet-none
Allow user_ns trait to be None

The Dict trait converts None to an empty dict, which caused the application to pass in a user_ns to the shell, which then behaves slightly differently, creating a DummyMod instance.
87d41d7
@minrk minrk 1.1 backport stats 7bdb1ae
@minrk minrk don't upload to GitHub in release script
GitHub doesn't have an API for it at the moment
3975d00
@minrk minrk Merge pull request #4190 from minrk/byebye2.6
update version-check message in setup.py and IPython.__init__

clearer message that IPython no longer supports 2.6.
08e02c6
@takluyver takluyver Merge pull request #4186 from mmckerns/master
moved DummyMod to proper namespace to enable dill pickling
a96f9c4
@Carreau Carreau remove executable flag on soem files ccb3fe5
@Carreau Carreau Split exporter in to for ipynb->ipynb 4f0f98f
@Carreau Carreau some trailing whitespace 96e8f30
@Carreau Carreau import baseexporter in init 8106096
@Carreau Carreau Exporter -> TemplateExporter / BaseExporter f52dfb6
@Carreau Carreau fix 1 test 87c3fc1
@jdfreder jdfreder renamed: exporter.py -> template_exporter.py bb2dc10
@jdfreder jdfreder renamed: baseexporter.py -> exporter.py 962d234
@jdfreder jdfreder renamed: template_exporter.py -> templateexporter.py 1c76bd3
@jdfreder jdfreder Rebase changes made by hand 14cf5fe
@jdfreder jdfreder Check if class is an instance of Exporter, not TemplateExporter 310bbbe
@jdfreder jdfreder Fixed Travis, missing import in export.py 9eaff2f
@Carreau
Owner

#4175 was not merging cleanly anymore. This is just a rebase of it.

@Carreau Carreau reopened this
@Carreau
Owner

Damed github see the wrong commits.

@jdfreder
Owner

Another rebase ? :stuck_out_tongue: We should merge this soon, I'm tired of seeing this get rebased.

@jdfreder
Owner

I was able to rebase #4175 without github having trouble, should I close this one again?

@Carreau Carreau closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 9, 2013
  1. @minrk

    always fire LOCAL_IPS.extend(PUBLIC_IPS)

    minrk authored
    was in `else`, but should have been `finally` so it aways runs.
    
    
    Symptom was warnings in parallel.client about `127.0.1.1` not being this machine.
  2. @minrk

    update version-check message in setup.py and IPython.__init__

    minrk authored
    clearer message that IPython no longer supports 2.6.
  3. @minrk

    update Python version classifiers:

    minrk authored
    - drop specific 3.x
    - drop 2.6
  4. @minrk

    update README with dropped 2.6 and 3.2 support

    minrk authored
    also clarify the checkout steps in development install
  5. @takluyver

    Use Instance trait for user_ns instead of Dict.

    takluyver authored
    Instance(dict) is None by default, unlike Dict().
  6. @takluyver

    Add a test for kernel started without user_ns kwarg.

    takluyver authored
    user_module should not be an instance of DummyMod
  7. @ivanov

    Merge pull request #4189 from minrk/localinterfaces-finally

    ivanov authored
    always fire LOCAL_IPS.extend(PUBLIC_IPS)
  8. @minrk

    Merge pull request #4188 from takluyver/dict-traitlet-none

    minrk authored
    Allow user_ns trait to be None
    
    The Dict trait converts None to an empty dict, which caused the application to pass in a user_ns to the shell, which then behaves slightly differently, creating a DummyMod instance.
Commits on Sep 10, 2013
  1. @minrk

    1.1 backport stats

    minrk authored
  2. @minrk

    don't upload to GitHub in release script

    minrk authored
    GitHub doesn't have an API for it at the moment
  3. @minrk

    Merge pull request #4190 from minrk/byebye2.6

    minrk authored
    update version-check message in setup.py and IPython.__init__
    
    clearer message that IPython no longer supports 2.6.
Commits on Sep 11, 2013
  1. @takluyver

    Merge pull request #4186 from mmckerns/master

    takluyver authored
    moved DummyMod to proper namespace to enable dill pickling
Commits on Sep 12, 2013
  1. @Carreau
  2. @Carreau
  3. @Carreau

    some trailing whitespace

    Carreau authored
  4. @Carreau

    import baseexporter in init

    Carreau authored
  5. @Carreau
  6. @Carreau

    fix 1 test

    Carreau authored
  7. @jdfreder @Carreau

    renamed: exporter.py -> template_exporter.py

    jdfreder authored Carreau committed
  8. @jdfreder @Carreau

    renamed: baseexporter.py -> exporter.py

    jdfreder authored Carreau committed
  9. @jdfreder @Carreau

    renamed: template_exporter.py -> templateexporter.py

    jdfreder authored Carreau committed
  10. @jdfreder @Carreau

    Rebase changes made by hand

    jdfreder authored Carreau committed
  11. @jdfreder @Carreau
  12. @jdfreder @Carreau

    Fixed Travis, missing import in export.py

    jdfreder authored Carreau committed
This page is out of date. Refresh to see the latest.
Showing with 551 additions and 324 deletions.
  1. +2 −2 IPython/__init__.py
  2. +0 −3  IPython/core/release.py
  3. +1 −1  IPython/core/shellapp.py
  4. +1 −1  IPython/kernel/zmq/ipkernel.py
  5. +30 −2 IPython/kernel/zmq/tests/test_start_kernel.py
  6. +2 −1  IPython/nbconvert/exporters/__init__.py
  7. +2 −1  IPython/nbconvert/exporters/export.py
  8. +46 −285 IPython/nbconvert/exporters/exporter.py
  9. +2 −2 IPython/nbconvert/exporters/html.py
  10. +2 −2 IPython/nbconvert/exporters/latex.py
  11. +2 −2 IPython/nbconvert/exporters/markdown.py
  12. +2 −2 IPython/nbconvert/exporters/python.py
  13. +2 −2 IPython/nbconvert/exporters/rst.py
  14. +2 −2 IPython/nbconvert/exporters/slides.py
  15. +315 −0 IPython/nbconvert/exporters/templateexporter.py
  16. +1 −1  IPython/nbconvert/exporters/tests/base.py
  17. +1 −1  IPython/nbconvert/exporters/tests/test_export.py
  18. +4 −4 IPython/nbconvert/exporters/tests/test_exporter.py
  19. +1 −1  IPython/nbconvert/filters/__init__.py
  20. +1 −1  IPython/nbconvert/nbconvertapp.py
  21. +1 −1  IPython/utils/localinterfaces.py
  22. +4 −1 README.rst
  23. +121 −0 docs/source/whatsnew/github-stats-1.0.rst
  24. +4 −6 setup.py
  25. +2 −0  tools/release
View
4 IPython/__init__.py
@@ -28,8 +28,8 @@
#-----------------------------------------------------------------------------
# Don't forget to also update setup.py when this changes!
-if sys.version[0:3] < '2.6':
- raise ImportError('Python Version 2.6 or above is required for IPython.')
+if sys.version_info[:2] < (2,7):
+ raise ImportError('IPython requires Python Version 2.7 or above.')
# Make it easy to import extensions - they are always directly on pythonpath.
# Therefore, non-IPython modules can be added to extensions directory.
View
3  IPython/core/release.py
@@ -141,11 +141,8 @@
'License :: OSI Approved :: BSD License',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.2',
- 'Programming Language :: Python :: 3.3',
'Topic :: System :: Distributed Computing',
'Topic :: System :: Shells'
]
View
2  IPython/core/shellapp.py
@@ -201,7 +201,7 @@ def _extra_extension_changed(self, name, old, new):
)
shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
- user_ns = Dict(default_value=None)
+ user_ns = Instance(dict, args=None, allow_none=True)
def _user_ns_changed(self, name, old, new):
if self.shell is not None:
self.shell.user_ns = new
View
2  IPython/kernel/zmq/ipkernel.py
@@ -87,7 +87,7 @@ def _user_module_changed(self, name, old, new):
if self.shell is not None:
self.shell.user_module = new
- user_ns = Dict(default_value=None)
+ user_ns = Instance(dict, args=None, allow_none=True)
def _user_ns_changed(self, name, old, new):
if self.shell is not None:
self.shell.user_ns = new
View
32 IPython/kernel/zmq/tests/test_start_kernel.py
@@ -8,10 +8,38 @@ def test_ipython_start_kernel_userns():
cmd = ('from IPython import start_kernel\n'
'ns = {"tre": 123}\n'
'start_kernel(user_ns=ns)')
-
+
with setup_kernel(cmd) as client:
msg_id = client.object_info('tre')
msg = client.get_shell_msg(block=True, timeout=TIMEOUT)
content = msg['content']
assert content['found']
- nt.assert_equal(content['string_form'], u'123')
+ nt.assert_equal(content['string_form'], u'123')
+
+ # user_module should be an instance of DummyMod
+ msg_id = client.execute("usermod = get_ipython().user_module")
+ msg = client.get_shell_msg(block=True, timeout=TIMEOUT)
+ content = msg['content']
+ nt.assert_equal(content['status'], u'ok')
+ msg_id = client.object_info('usermod')
+ msg = client.get_shell_msg(block=True, timeout=TIMEOUT)
+ content = msg['content']
+ assert content['found']
+ nt.assert_in('DummyMod', content['string_form'])
+
+def test_ipython_start_kernel_no_userns():
+ # Issue #4188 - user_ns should be passed to shell as None, not {}
+ cmd = ('from IPython import start_kernel\n'
+ 'start_kernel()')
+
+ with setup_kernel(cmd) as client:
+ # user_module should not be an instance of DummyMod
+ msg_id = client.execute("usermod = get_ipython().user_module")
+ msg = client.get_shell_msg(block=True, timeout=TIMEOUT)
+ content = msg['content']
+ nt.assert_equal(content['status'], u'ok')
+ msg_id = client.object_info('usermod')
+ msg = client.get_shell_msg(block=True, timeout=TIMEOUT)
+ content = msg['content']
+ assert content['found']
+ nt.assert_not_in('DummyMod', content['string_form'])
View
3  IPython/nbconvert/exporters/__init__.py 100755 → 100644
@@ -1,8 +1,9 @@
from .export import *
from .html import HTMLExporter
from .slides import SlidesExporter
-from .exporter import Exporter
+from .templateexporter import TemplateExporter
from .latex import LatexExporter
from .markdown import MarkdownExporter
from .python import PythonExporter
from .rst import RSTExporter
+from .exporter import Exporter
View
3  IPython/nbconvert/exporters/export.py 100755 → 100644
@@ -19,6 +19,7 @@
from IPython.config import Config
from .exporter import Exporter
+from .templateexporter import TemplateExporter
from .html import HTMLExporter
from .slides import SlidesExporter
from .latex import LatexExporter
@@ -122,7 +123,7 @@ def export(exporter, nb, **kw):
return output, resources
exporter_map = dict(
- custom=Exporter,
+ custom=TemplateExporter,
html=HTMLExporter,
slides=SlidesExporter,
latex=LatexExporter,
View
331 IPython/nbconvert/exporters/exporter.py 100755 → 100644
@@ -19,58 +19,21 @@
# Stdlib imports
import io
import os
-import inspect
import copy
import collections
import datetime
-# other libs/dependencies
-from jinja2 import Environment, FileSystemLoader, ChoiceLoader, TemplateNotFound
# IPython imports
from IPython.config.configurable import LoggingConfigurable
from IPython.config import Config
from IPython.nbformat import current as nbformat
-from IPython.utils.traitlets import MetaHasTraits, DottedObjectName, Unicode, List, Dict, Any
+from IPython.utils.traitlets import MetaHasTraits, Unicode, List
from IPython.utils.importstring import import_item
-from IPython.utils import text
-from IPython.utils import py3compat
+from IPython.utils import text, py3compat
from IPython.nbconvert import preprocessors as nbpreprocessors
-from IPython.nbconvert import filters
-#-----------------------------------------------------------------------------
-# Globals and constants
-#-----------------------------------------------------------------------------
-
-#Jinja2 extensions to load.
-JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
-
-default_filters = {
- 'indent': text.indent,
- 'markdown2html': filters.markdown2html,
- 'ansi2html': filters.ansi2html,
- 'filter_data_type': filters.DataTypeFilter,
- 'get_lines': filters.get_lines,
- 'highlight2html': filters.highlight2html,
- 'highlight2latex': filters.highlight2latex,
- 'ipython2python': filters.ipython2python,
- 'posix_path': filters.posix_path,
- 'markdown2latex': filters.markdown2latex,
- 'markdown2rst': filters.markdown2rst,
- 'comment_lines': filters.comment_lines,
- 'strip_ansi': filters.strip_ansi,
- 'strip_dollars': filters.strip_dollars,
- 'strip_files_prefix': filters.strip_files_prefix,
- 'html2text' : filters.html2text,
- 'add_anchor': filters.add_anchor,
- 'ansi2latex': filters.ansi2latex,
- 'strip_math_space': filters.strip_math_space,
- 'wrap_text': filters.wrap_text,
- 'escape_latex': filters.escape_latex,
- 'citation2latex': filters.citation2latex,
- 'path2url': filters.path2url,
-}
#-----------------------------------------------------------------------------
# Class
@@ -83,70 +46,23 @@ def __missing__(self, key):
class Exporter(LoggingConfigurable):
"""
- Exports notebooks into other file formats. Uses Jinja 2 templating engine
- to output new formats. Inherit from this class if you are creating a new
- template type along with new filters/preprocessors. If the filters/
- preprocessors provided by default suffice, there is no need to inherit from
- this class. Instead, override the template_file and file_extension
- traits via a config file.
-
- {filters}
+ Exporter class that only converts from notebook to notebook
+ by applying the preprocessors and providing basic methods for
+ reading a notebook from different sources.
"""
-
- # finish the docstring
- __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
-
- template_file = Unicode(u'default',
- config=True,
- help="Name of the template file to use")
- def _template_file_changed(self, name, old, new):
- if new=='default':
- self.template_file = self.default_template
- else:
- self.template_file = new
- self.template = None
- self._load_template()
-
- default_template = Unicode(u'')
- template = Any()
- environment = Any()
+ # finish the docstring
file_extension = Unicode(
- 'txt', config=True,
+ 'txt', config=True,
help="Extension of the file that should be written to disk"
)
- template_path = List(['.'], config=True)
- def _template_path_changed(self, name, old, new):
- self._load_template()
-
- default_template_path = Unicode(
- os.path.join("..", "templates"),
- help="Path where the template files are located.")
-
- template_skeleton_path = Unicode(
- os.path.join("..", "templates", "skeleton"),
- help="Path where the template skeleton files are located.")
-
- #Jinja block definitions
- jinja_comment_block_start = Unicode("", config=True)
- jinja_comment_block_end = Unicode("", config=True)
- jinja_variable_block_start = Unicode("", config=True)
- jinja_variable_block_end = Unicode("", config=True)
- jinja_logic_block_start = Unicode("", config=True)
- jinja_logic_block_end = Unicode("", config=True)
-
- #Extension that the template files use.
- template_extension = Unicode(".tpl", config=True)
-
#Configurability, allows the user to easily add filters and preprocessors.
preprocessors = List(config=True,
help="""List of preprocessors, by name or namespace, to enable.""")
- filters = Dict(config=True,
- help="""Dictionary of filters, by name and namespace, to add to the Jinja
- environment.""")
+ _preprocessors = None
default_preprocessors = List([nbpreprocessors.coalesce_streams,
nbpreprocessors.SVG2PDFPreprocessor,
@@ -160,36 +76,28 @@ def _template_path_changed(self, name, old, new):
instance, or type.""")
- def __init__(self, config=None, extra_loaders=None, **kw):
+ def __init__(self, config=None, **kw):
"""
Public constructor
-
+
Parameters
----------
config : config
User configuration instance.
- extra_loaders : list[of Jinja Loaders]
- ordered list of Jinja loader to find templates. Will be tried in order
- before the default FileSystem ones.
- template : str (optional, kw arg)
- Template to use when exporting.
"""
if not config:
config = self.default_config
-
+
super(Exporter, self).__init__(config=config, **kw)
#Init
- self._init_template()
- self._init_environment(extra_loaders=extra_loaders)
self._init_preprocessors()
- self._init_filters()
@property
def default_config(self):
return Config()
-
+
def _config_changed(self, name, old, new):
"""When setting config, make sure to start with our default_config"""
c = self.default_config
@@ -198,83 +106,39 @@ def _config_changed(self, name, old, new):
if c != old:
self.config = c
super(Exporter, self)._config_changed(name, old, c)
-
-
- def _load_template(self):
- """Load the Jinja template object from the template file
-
- This is a no-op if the template attribute is already defined,
- or the Jinja environment is not setup yet.
-
- This is triggered by various trait changes that would change the template.
- """
- if self.template is not None:
- return
- # called too early, do nothing
- if self.environment is None:
- return
- # Try different template names during conversion. First try to load the
- # template by name with extension added, then try loading the template
- # as if the name is explicitly specified, then try the name as a
- # 'flavor', and lastly just try to load the template by module name.
- module_name = self.__module__.rsplit('.', 1)[-1]
- try_names = []
- if self.template_file:
- try_names.extend([
- self.template_file + self.template_extension,
- self.template_file,
- module_name + '_' + self.template_file + self.template_extension,
- ])
- try_names.append(module_name + self.template_extension)
- for try_name in try_names:
- self.log.debug("Attempting to load template %s", try_name)
- try:
- self.template = self.environment.get_template(try_name)
- except (TemplateNotFound, IOError):
- pass
- except Exception as e:
- self.log.warn("Unexpected exception loading template: %s", try_name, exc_info=True)
- else:
- self.log.info("Loaded template %s", try_name)
- break
-
- def from_notebook_node(self, nb, resources=None, **kw):
+
+
+ def from_notebook_node(self, nb, resources=None):
"""
Convert a notebook from a notebook node instance.
-
+
Parameters
----------
nb : Notebook node
- resources : dict (**kw)
- of additional resources that can be accessed read/write by
- preprocessors and filters.
+ resources : dict (**kw)
+ of additional resources that can be accessed read/write by
+ preprocessors.
"""
nb_copy = copy.deepcopy(nb)
resources = self._init_resources(resources)
# Preprocess
- nb_copy, resources = self._preprocess(nb_copy, resources)
+ nb_copy, resources = self._transform(nb_copy, resources)
- self._load_template()
-
- if self.template is not None:
- output = self.template.render(nb=nb_copy, resources=resources)
- else:
- raise IOError('template file "%s" could not be found' % self.template_file)
- return output, resources
+ return nb_copy, resources
def from_filename(self, filename, resources=None, **kw):
"""
Convert a notebook from a notebook file.
-
+
Parameters
----------
filename : str
Full filename of the notebook file to open and convert.
"""
- #Pull the metadata from the filesystem.
+ # Pull the metadata from the filesystem.
if resources is None:
resources = ResourcesDict()
if not 'metadata' in resources or resources['metadata'] == '':
@@ -285,15 +149,15 @@ def from_filename(self, filename, resources=None, **kw):
modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
resources['metadata']['modified_date'] = modified_date.strftime(text.date_format)
-
+
with io.open(filename) as f:
- return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources,**kw)
+ return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources, **kw)
def from_file(self, file_stream, resources=None, **kw):
"""
Convert a notebook from a notebook file.
-
+
Parameters
----------
file_stream : file-like object
@@ -305,11 +169,11 @@ def from_file(self, file_stream, resources=None, **kw):
def register_preprocessor(self, preprocessor, enabled=False):
"""
Register a preprocessor.
- Preprocessors are classes that act upon the notebook before it is
- passed into the Jinja templating engine. Preprocessors are also
+ preprocessors are classes that act upon the notebook before it is
+ passed into the Jinja templating engine. preprocessors are also
capable of passing additional information to the Jinja
templating engine.
-
+
Parameters
----------
preprocessor : preprocessor
@@ -321,13 +185,13 @@ def register_preprocessor(self, preprocessor, enabled=False):
#Handle preprocessor's registration based on it's type
if constructed and isinstance(preprocessor, py3compat.string_types):
- #Preprocessor is a string, import the namespace and recursively call
+ #preprocessor is a string, import the namespace and recursively call
#this register_preprocessor method
preprocessor_cls = import_item(preprocessor)
return self.register_preprocessor(preprocessor_cls, enabled)
-
+
if constructed and hasattr(preprocessor, '__call__'):
- #Preprocessor is a function, no need to construct it.
+ #preprocessor is a function, no need to construct it.
#Register and return the preprocessor.
if enabled:
preprocessor.enabled = True
@@ -335,114 +199,27 @@ def register_preprocessor(self, preprocessor, enabled=False):
return preprocessor
elif isclass and isinstance(preprocessor, MetaHasTraits):
- #Preprocessor is configurable. Make sure to pass in new default for
+ #preprocessor is configurable. Make sure to pass in new default for
#the enabled flag if one was specified.
self.register_preprocessor(preprocessor(parent=self), enabled)
elif isclass:
- #Preprocessor is not configurable, construct it
+ #preprocessor is not configurable, construct it
self.register_preprocessor(preprocessor(), enabled)
else:
- #Preprocessor is an instance of something without a __call__
- #attribute.
+ #preprocessor is an instance of something without a __call__
+ #attribute.
raise TypeError('preprocessor')
- def register_filter(self, name, jinja_filter):
- """
- Register a filter.
- A filter is a function that accepts and acts on one string.
- The filters are accesible within the Jinja templating engine.
-
- Parameters
- ----------
- name : str
- name to give the filter in the Jinja engine
- filter : filter
- """
- if jinja_filter is None:
- raise TypeError('filter')
- isclass = isinstance(jinja_filter, type)
- constructed = not isclass
-
- #Handle filter's registration based on it's type
- if constructed and isinstance(jinja_filter, py3compat.string_types):
- #filter is a string, import the namespace and recursively call
- #this register_filter method
- filter_cls = import_item(jinja_filter)
- return self.register_filter(name, filter_cls)
-
- if constructed and hasattr(jinja_filter, '__call__'):
- #filter is a function, no need to construct it.
- self.environment.filters[name] = jinja_filter
- return jinja_filter
-
- elif isclass and isinstance(jinja_filter, MetaHasTraits):
- #filter is configurable. Make sure to pass in new default for
- #the enabled flag if one was specified.
- filter_instance = jinja_filter(parent=self)
- self.register_filter(name, filter_instance )
-
- elif isclass:
- #filter is not configurable, construct it
- filter_instance = jinja_filter()
- self.register_filter(name, filter_instance)
-
- else:
- #filter is an instance of something without a __call__
- #attribute.
- raise TypeError('filter')
-
-
- def _init_template(self):
- """
- Make sure a template name is specified. If one isn't specified, try to
- build one from the information we know.
- """
- self._template_file_changed('template_file', self.template_file, self.template_file)
-
-
- def _init_environment(self, extra_loaders=None):
- """
- Create the Jinja templating environment.
- """
- here = os.path.dirname(os.path.realpath(__file__))
- loaders = []
- if extra_loaders:
- loaders.extend(extra_loaders)
-
- paths = self.template_path
- paths.extend([os.path.join(here, self.default_template_path),
- os.path.join(here, self.template_skeleton_path)])
- loaders.append(FileSystemLoader(paths))
-
- self.environment = Environment(
- loader= ChoiceLoader(loaders),
- extensions=JINJA_EXTENSIONS
- )
-
- #Set special Jinja2 syntax that will not conflict with latex.
- if self.jinja_logic_block_start:
- self.environment.block_start_string = self.jinja_logic_block_start
- if self.jinja_logic_block_end:
- self.environment.block_end_string = self.jinja_logic_block_end
- if self.jinja_variable_block_start:
- self.environment.variable_start_string = self.jinja_variable_block_start
- if self.jinja_variable_block_end:
- self.environment.variable_end_string = self.jinja_variable_block_end
- if self.jinja_comment_block_start:
- self.environment.comment_start_string = self.jinja_comment_block_start
- if self.jinja_comment_block_end:
- self.environment.comment_end_string = self.jinja_comment_block_end
-
-
def _init_preprocessors(self):
"""
Register all of the preprocessors needed for this exporter, disabled
unless specified explicitly.
"""
- self._preprocessors = []
+ if self._preprocessors is None:
+ self._preprocessors = []
#Load default preprocessors (not necessarly enabled by default).
if self.default_preprocessors:
@@ -453,21 +230,6 @@ def _init_preprocessors(self):
if self.preprocessors:
for preprocessor in self.preprocessors:
self.register_preprocessor(preprocessor, enabled=True)
-
-
- def _init_filters(self):
- """
- Register all of the filters required for the exporter.
- """
-
- #Add default filters to the Jinja2 environment
- for key, value in default_filters.items():
- self.register_filter(key, value)
-
- #Load user filters. Overwrite existing filters if need be.
- if self.filters:
- for key, user_filter in self.filters.items():
- self.register_filter(key, user_filter)
def _init_resources(self, resources):
@@ -478,7 +240,7 @@ def _init_resources(self, resources):
if not isinstance(resources, ResourcesDict):
new_resources = ResourcesDict()
new_resources.update(resources)
- resources = new_resources
+ resources = new_resources
#Make sure the metadata extension exists in resources
if 'metadata' in resources:
@@ -486,29 +248,28 @@ def _init_resources(self, resources):
resources['metadata'] = ResourcesDict(resources['metadata'])
else:
resources['metadata'] = ResourcesDict()
- if not resources['metadata']['name']:
+ if not resources['metadata']['name']:
resources['metadata']['name'] = 'Notebook'
#Set the output extension
resources['output_extension'] = self.file_extension
return resources
-
- def _preprocess(self, nb, resources):
+
+ def _transform(self, nb, resources):
"""
Preprocess the notebook before passing it into the Jinja engine.
- To preprocess the notebook is to apply all of the
-
+ To preprocess the notebook is to apply all of the
+
Parameters
----------
nb : notebook node
notebook that is being exported.
resources : a dict of additional resources that
can be accessed read/write by preprocessors
- and filters.
"""
-
- # Do a copy.deepcopy first,
+
+ # Do a copy.deepcopy first,
# we are never safe enough with what the preprocessors could do.
nbc = copy.deepcopy(nb)
resc = copy.deepcopy(resources)
View
4 IPython/nbconvert/exporters/html.py
@@ -19,13 +19,13 @@
from IPython.nbconvert import preprocessors
from IPython.config import Config
-from .exporter import Exporter
+from .templateexporter import TemplateExporter
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
-class HTMLExporter(Exporter):
+class HTMLExporter(TemplateExporter):
"""
Exports a basic HTML document. This exporter assists with the export of
HTML. Inherit from it if you are writing your own HTML template and need
View
4 IPython/nbconvert/exporters/latex.py 100755 → 100644
@@ -24,13 +24,13 @@
from IPython.config import Config
from IPython.nbconvert import filters, preprocessors
-from .exporter import Exporter
+from .templateexporter import TemplateExporter
#-----------------------------------------------------------------------------
# Classes and functions
#-----------------------------------------------------------------------------
-class LatexExporter(Exporter):
+class LatexExporter(TemplateExporter):
"""
Exports to a Latex template. Inherit from this class if your template is
LaTeX based and you need custom tranformers/filters. Inherit from it if
View
4 IPython/nbconvert/exporters/markdown.py
@@ -16,13 +16,13 @@
from IPython.config import Config
from IPython.utils.traitlets import Unicode
-from .exporter import Exporter
+from .templateexporter import TemplateExporter
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
-class MarkdownExporter(Exporter):
+class MarkdownExporter(TemplateExporter):
"""
Exports to a markdown document (.md)
"""
View
4 IPython/nbconvert/exporters/python.py
@@ -15,13 +15,13 @@
from IPython.utils.traitlets import Unicode
-from .exporter import Exporter
+from .templateexporter import TemplateExporter
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
-class PythonExporter(Exporter):
+class PythonExporter(TemplateExporter):
"""
Exports a Python code file.
"""
View
4 IPython/nbconvert/exporters/rst.py
@@ -16,13 +16,13 @@
from IPython.utils.traitlets import Unicode
from IPython.config import Config
-from .exporter import Exporter
+from .templateexporter import TemplateExporter
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
-class RSTExporter(Exporter):
+class RSTExporter(TemplateExporter):
"""
Exports restructured text documents.
"""
View
4 IPython/nbconvert/exporters/slides.py
@@ -19,13 +19,13 @@
from IPython.nbconvert import preprocessors
from IPython.config import Config
-from .exporter import Exporter
+from .templateexporter import TemplateExporter
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
-class SlidesExporter(Exporter):
+class SlidesExporter(TemplateExporter):
"""
Exports slides
"""
View
315 IPython/nbconvert/exporters/templateexporter.py
@@ -0,0 +1,315 @@
+"""This module defines Exporter, a highly configurable converter
+that uses Jinja2 to export notebook files into different formats.
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from __future__ import print_function, absolute_import
+
+# Stdlib imports
+import os
+
+# other libs/dependencies
+from jinja2 import Environment, FileSystemLoader, ChoiceLoader, TemplateNotFound
+
+# IPython imports
+from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Dict, Any
+from IPython.utils.importstring import import_item
+from IPython.utils import py3compat, text
+
+from IPython.nbconvert import filters
+from .exporter import Exporter
+
+#-----------------------------------------------------------------------------
+# Globals and constants
+#-----------------------------------------------------------------------------
+
+#Jinja2 extensions to load.
+JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
+
+default_filters = {
+ 'indent': text.indent,
+ 'markdown2html': filters.markdown2html,
+ 'ansi2html': filters.ansi2html,
+ 'filter_data_type': filters.DataTypeFilter,
+ 'get_lines': filters.get_lines,
+ 'highlight2html': filters.highlight2html,
+ 'highlight2latex': filters.highlight2latex,
+ 'ipython2python': filters.ipython2python,
+ 'posix_path': filters.posix_path,
+ 'markdown2latex': filters.markdown2latex,
+ 'markdown2rst': filters.markdown2rst,
+ 'comment_lines': filters.comment_lines,
+ 'strip_ansi': filters.strip_ansi,
+ 'strip_dollars': filters.strip_dollars,
+ 'strip_files_prefix': filters.strip_files_prefix,
+ 'html2text' : filters.html2text,
+ 'add_anchor': filters.add_anchor,
+ 'ansi2latex': filters.ansi2latex,
+ 'strip_math_space': filters.strip_math_space,
+ 'wrap_text': filters.wrap_text,
+ 'escape_latex': filters.escape_latex,
+ 'citation2latex': filters.citation2latex,
+ 'path2url': filters.path2url,
+}
+
+#-----------------------------------------------------------------------------
+# Class
+#-----------------------------------------------------------------------------
+
+class TemplateExporter(Exporter):
+ """
+ Exports notebooks into other file formats. Uses Jinja 2 templating engine
+ to output new formats. Inherit from this class if you are creating a new
+ template type along with new filters/preprocessors. If the filters/
+ preprocessors provided by default suffice, there is no need to inherit from
+ this class. Instead, override the template_file and file_extension
+ traits via a config file.
+
+ {filters}
+ """
+
+ # finish the docstring
+ __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
+
+
+ template_file = Unicode(u'default',
+ config=True,
+ help="Name of the template file to use")
+ def _template_file_changed(self, name, old, new):
+ if new == 'default':
+ self.template_file = self.default_template
+ else:
+ self.template_file = new
+ self.template = None
+ self._load_template()
+
+ default_template = Unicode(u'')
+ template = Any()
+ environment = Any()
+
+ template_path = List(['.'], config=True)
+ def _template_path_changed(self, name, old, new):
+ self._load_template()
+
+ default_template_path = Unicode(
+ os.path.join("..", "templates"),
+ help="Path where the template files are located.")
+
+ template_skeleton_path = Unicode(
+ os.path.join("..", "templates", "skeleton"),
+ help="Path where the template skeleton files are located.")
+
+ #Jinja block definitions
+ jinja_comment_block_start = Unicode("", config=True)
+ jinja_comment_block_end = Unicode("", config=True)
+ jinja_variable_block_start = Unicode("", config=True)
+ jinja_variable_block_end = Unicode("", config=True)
+ jinja_logic_block_start = Unicode("", config=True)
+ jinja_logic_block_end = Unicode("", config=True)
+
+ #Extension that the template files use.
+ template_extension = Unicode(".tpl", config=True)
+
+ filters = Dict(config=True,
+ help="""Dictionary of filters, by name and namespace, to add to the Jinja
+ environment.""")
+
+
+ def __init__(self, config=None, extra_loaders=None, **kw):
+ """
+ Public constructor
+
+ Parameters
+ ----------
+ config : config
+ User configuration instance.
+ extra_loaders : list[of Jinja Loaders]
+ ordered list of Jinja loader to find templates. Will be tried in order
+ before the default FileSystem ones.
+ template : str (optional, kw arg)
+ Template to use when exporting.
+ """
+ if not config:
+ config = self.default_config
+
+ super(Exporter, self).__init__(config=config, **kw)
+
+ #Init
+ self._init_template()
+ self._init_environment(extra_loaders=extra_loaders)
+ self._init_preprocessors()
+ self._init_filters()
+
+
+ def _load_template(self):
+ """Load the Jinja template object from the template file
+
+ This is a no-op if the template attribute is already defined,
+ or the Jinja environment is not setup yet.
+
+ This is triggered by various trait changes that would change the template.
+ """
+ if self.template is not None:
+ return
+ # called too early, do nothing
+ if self.environment is None:
+ return
+ # Try different template names during conversion. First try to load the
+ # template by name with extension added, then try loading the template
+ # as if the name is explicitly specified, then try the name as a
+ # 'flavor', and lastly just try to load the template by module name.
+ module_name = self.__module__.rsplit('.', 1)[-1]
+ try_names = []
+ if self.template_file:
+ try_names.extend([
+ self.template_file + self.template_extension,
+ self.template_file,
+ module_name + '_' + self.template_file + self.template_extension,
+ ])
+ try_names.append(module_name + self.template_extension)
+ for try_name in try_names:
+ self.log.debug("Attempting to load template %s", try_name)
+ try:
+ self.template = self.environment.get_template(try_name)
+ except (TemplateNotFound, IOError):
+ pass
+ except Exception as e:
+ self.log.warn("Unexpected exception loading template: %s", try_name, exc_info=True)
+ else:
+ self.log.info("Loaded template %s", try_name)
+ break
+
+ def from_notebook_node(self, nb, resources=None, **kw):
+ """
+ Convert a notebook from a notebook node instance.
+
+ Parameters
+ ----------
+ nb : Notebook node
+ resources : dict (**kw)
+ of additional resources that can be accessed read/write by
+ preprocessors and filters.
+ """
+ nb_copy, resources = super(TemplateExporter, self).from_notebook_node(nb, resources, **kw)
+
+ self._load_template()
+
+ if self.template is not None:
+ output = self.template.render(nb=nb_copy, resources=resources)
+ else:
+ raise IOError('template file "%s" could not be found' % self.template_file)
+ return output, resources
+
+
+ def register_filter(self, name, jinja_filter):
+ """
+ Register a filter.
+ A filter is a function that accepts and acts on one string.
+ The filters are accesible within the Jinja templating engine.
+
+ Parameters
+ ----------
+ name : str
+ name to give the filter in the Jinja engine
+ filter : filter
+ """
+ if jinja_filter is None:
+ raise TypeError('filter')
+ isclass = isinstance(jinja_filter, type)
+ constructed = not isclass
+
+ #Handle filter's registration based on it's type
+ if constructed and isinstance(jinja_filter, py3compat.string_types):
+ #filter is a string, import the namespace and recursively call
+ #this register_filter method
+ filter_cls = import_item(jinja_filter)
+ return self.register_filter(name, filter_cls)
+
+ if constructed and hasattr(jinja_filter, '__call__'):
+ #filter is a function, no need to construct it.
+ self.environment.filters[name] = jinja_filter
+ return jinja_filter
+
+ elif isclass and isinstance(jinja_filter, MetaHasTraits):
+ #filter is configurable. Make sure to pass in new default for
+ #the enabled flag if one was specified.
+ filter_instance = jinja_filter(parent=self)
+ self.register_filter(name, filter_instance )
+
+ elif isclass:
+ #filter is not configurable, construct it
+ filter_instance = jinja_filter()
+ self.register_filter(name, filter_instance)
+
+ else:
+ #filter is an instance of something without a __call__
+ #attribute.
+ raise TypeError('filter')
+
+
+ def _init_template(self):
+ """
+ Make sure a template name is specified. If one isn't specified, try to
+ build one from the information we know.
+ """
+ self._template_file_changed('template_file', self.template_file, self.template_file)
+
+
+ def _init_environment(self, extra_loaders=None):
+ """
+ Create the Jinja templating environment.
+ """
+ here = os.path.dirname(os.path.realpath(__file__))
+ loaders = []
+ if extra_loaders:
+ loaders.extend(extra_loaders)
+
+ paths = self.template_path
+ paths.extend([os.path.join(here, self.default_template_path),
+ os.path.join(here, self.template_skeleton_path)])
+ loaders.append(FileSystemLoader(paths))
+
+ self.environment = Environment(
+ loader= ChoiceLoader(loaders),
+ extensions=JINJA_EXTENSIONS
+ )
+
+ #Set special Jinja2 syntax that will not conflict with latex.
+ if self.jinja_logic_block_start:
+ self.environment.block_start_string = self.jinja_logic_block_start
+ if self.jinja_logic_block_end:
+ self.environment.block_end_string = self.jinja_logic_block_end
+ if self.jinja_variable_block_start:
+ self.environment.variable_start_string = self.jinja_variable_block_start
+ if self.jinja_variable_block_end:
+ self.environment.variable_end_string = self.jinja_variable_block_end
+ if self.jinja_comment_block_start:
+ self.environment.comment_start_string = self.jinja_comment_block_start
+ if self.jinja_comment_block_end:
+ self.environment.comment_end_string = self.jinja_comment_block_end
+
+
+ def _init_filters(self):
+ """
+ Register all of the filters required for the exporter.
+ """
+
+ #Add default filters to the Jinja2 environment
+ for key, value in default_filters.items():
+ self.register_filter(key, value)
+
+ #Load user filters. Overwrite existing filters if need be.
+ if self.filters:
+ for key, user_filter in self.filters.items():
+ self.register_filter(key, user_filter)
View
2  IPython/nbconvert/exporters/tests/base.py
@@ -27,4 +27,4 @@ class ExportersTestsBase(TestsBase):
def _get_notebook(self):
return os.path.join(self._get_files_path(), 'notebook2.ipynb')
-
+
View
2  IPython/nbconvert/exporters/tests/test_export.py
@@ -99,4 +99,4 @@ def test_no_exporter(self):
(output, resources) = export(None, self._get_notebook())
except TypeError:
pass
-
+
View
8 IPython/nbconvert/exporters/tests/test_exporter.py
@@ -18,7 +18,7 @@
from .base import ExportersTestsBase
from .cheese import CheesePreprocessor
-from ..exporter import Exporter
+from ..templateexporter import TemplateExporter
#-----------------------------------------------------------------------------
@@ -31,9 +31,9 @@ class TestExporter(ExportersTestsBase):
def test_constructor(self):
"""
- Can an Exporter be constructed?
+ Can an TemplateExporter be constructed?
"""
- Exporter()
+ TemplateExporter()
def test_export(self):
@@ -104,5 +104,5 @@ def test_preprocessor_via_method(self):
def _make_exporter(self, config=None):
#Create the exporter instance, make sure to set a template name since
#the base Exporter doesn't have a template associated with it.
- exporter = Exporter(config=config, template_file='python')
+ exporter = TemplateExporter(config=config, template_file='python')
return exporter
View
2  IPython/nbconvert/filters/__init__.py
@@ -1,7 +1,7 @@
from .ansi import *
+from .citation import *
from .datatypefilter import *
from .highlight import *
from .latex import *
from .markdown import *
from .strings import *
-from .citation import *
View
2  IPython/nbconvert/nbconvertapp.py
@@ -59,7 +59,7 @@ def validate(self, obj, value):
nbconvert_aliases.update(base_aliases)
nbconvert_aliases.update({
'to' : 'NbConvertApp.export_format',
- 'template' : 'Exporter.template_file',
+ 'template' : 'TemplateExporter.template_file',
'writer' : 'NbConvertApp.writer_class',
'post': 'NbConvertApp.postprocessor_class',
'output': 'NbConvertApp.output_base',
View
2  IPython/utils/localinterfaces.py
@@ -43,7 +43,7 @@
PUBLIC_IPS = socket.gethostbyname_ex(socket.gethostname() + '.local')[2]
except socket.error:
pass
-else:
+finally:
PUBLIC_IPS = uniq_stable(PUBLIC_IPS)
LOCAL_IPS.extend(PUBLIC_IPS)
View
5 README.rst
@@ -19,7 +19,8 @@ For full details, see the installation section of the manual. The basic parts
of IPython only need the Python standard library, but much of its more advanced
functionality requires extra packages.
-Officially, IPython requires Python version 2.6, 2.7, or 3.1 and above.
+Officially, IPython requires Python version 2.7, or 3.3 and above.
+IPython 1.x is the last IPython version to support Python 2.6 and 3.2.
Instant running
@@ -38,6 +39,8 @@ If you want to hack on certain parts, e.g. the IPython notebook, in a clean
environment (such as a virtualenv) you can use ``pip`` to grab the necessary
dependencies quickly::
+ $ git clone --recursive https://github.com/ipython/ipython.git
+ $ cd ipython
$ pip install -e ".[notebook]"
This installs the necessary packages and symlinks IPython into your current
View
121 docs/source/whatsnew/github-stats-1.0.rst
@@ -3,6 +3,127 @@
Issues closed in the 1.0 development cycle
==========================================
+Issues closed in 1.1
+--------------------
+
+GitHub stats for 2013/08/08 - 2013/09/09 (since 1.0)
+
+These lists are automatically generated, and may be incomplete or contain duplicates.
+
+The following 25 authors contributed 337 commits.
+
+* Benjamin Ragan-Kelley
+* Bing Xia
+* Bradley M. Froehle
+* Brian E. Granger
+* Damián Avila
+* dhirschfeld
+* Dražen Lučanin
+* gmbecker
+* Jake Vanderplas
+* Jason Grout
+* Jonathan Frederic
+* Kevin Burke
+* Kyle Kelley
+* Matt Henderson
+* Matthew Brett
+* Matthias Bussonnier
+* Pankaj Pandey
+* Paul Ivanov
+* rossant
+* Samuel Ainsworth
+* Stephan Rave
+* stonebig
+* Thomas Kluyver
+* Yaroslav Halchenko
+* Zachary Sailer
+
+
+We closed a total of 76 issues, 58 pull requests and 18 regular issues;
+this is the full list (generated with the script :file:`tools/github_stats.py`):
+
+Pull Requests (58):
+
+* :ghpull:`4188`: Allow user_ns trait to be None
+* :ghpull:`4189`: always fire LOCAL_IPS.extend(PUBLIC_IPS)
+* :ghpull:`4174`: various issues in markdown and rst templates
+* :ghpull:`4178`: add missing data_javascript
+* :ghpull:`4181`: nbconvert: Fix, sphinx template not removing new lines from headers
+* :ghpull:`4043`: don't 'restore_bytes' in from_JSON
+* :ghpull:`4163`: Fix for incorrect default encoding on Windows.
+* :ghpull:`4136`: catch javascript errors in any output
+* :ghpull:`4171`: add nbconvert config file when creating profiles
+* :ghpull:`4125`: Basic exercise of `ipython [subcommand] -h` and help-all
+* :ghpull:`4085`: nbconvert: Fix sphinx preprocessor date format string for Windows
+* :ghpull:`4159`: don't split `.cell` and `div.cell` CSS
+* :ghpull:`4158`: generate choices for `--gui` configurable from real mapping
+* :ghpull:`4065`: do not include specific css in embedable one
+* :ghpull:`4092`: nbconvert: Fix for unicode html headers, Windows + Python 2.x
+* :ghpull:`4074`: close Client sockets if connection fails
+* :ghpull:`4064`: Store default codemirror mode in only 1 place
+* :ghpull:`4104`: Add way to install MathJax to a particular profile
+* :ghpull:`4144`: help_end transformer shouldn't pick up ? in multiline string
+* :ghpull:`4143`: update example custom.js
+* :ghpull:`4142`: DOC: unwrap openssl line in public_server doc
+* :ghpull:`4141`: add files with a separate `add` call in backport_pr
+* :ghpull:`4137`: Restore autorestore option for storemagic
+* :ghpull:`4098`: pass profile-dir instead of profile name to Kernel
+* :ghpull:`4120`: support `input` in Python 2 kernels
+* :ghpull:`4088`: nbconvert: Fix coalescestreams line with incorrect nesting causing strange behavior
+* :ghpull:`4060`: only strip continuation prompts if regular prompts seen first
+* :ghpull:`4132`: Fixed name error bug in function safe_unicode in module py3compat.
+* :ghpull:`4121`: move test_kernel from IPython.zmq to IPython.kernel
+* :ghpull:`4118`: ZMQ heartbeat channel: catch EINTR exceptions and continue.
+* :ghpull:`4054`: use unicode for HTML export
+* :ghpull:`4106`: fix a couple of default block values
+* :ghpull:`4115`: Update docs on declaring a magic function
+* :ghpull:`4101`: restore accidentally removed EngineError
+* :ghpull:`4096`: minor docs changes
+* :ghpull:`4056`: respect `pylab_import_all` when `--pylab` specified at the command-line
+* :ghpull:`4091`: Make Qt console banner configurable
+* :ghpull:`4086`: fix missing errno import
+* :ghpull:`4030`: exclude `.git` in MANIFEST.in
+* :ghpull:`4047`: Use istype() when checking if canned object is a dict
+* :ghpull:`4031`: don't close_fds on Windows
+* :ghpull:`4029`: bson.Binary moved
+* :ghpull:`4035`: Fixed custom jinja2 templates being ignored when setting template_path
+* :ghpull:`4026`: small doc fix in nbconvert
+* :ghpull:`4016`: Fix IPython.start_* functions
+* :ghpull:`4021`: Fix parallel.client.View map() on numpy arrays
+* :ghpull:`4022`: DOC: fix links to matplotlib, notebook docs
+* :ghpull:`4018`: Fix warning when running IPython.kernel tests
+* :ghpull:`4019`: Test skipping without unicode paths
+* :ghpull:`4008`: Transform code before %prun/%%prun runs
+* :ghpull:`4014`: Fix typo in ipapp
+* :ghpull:`3987`: get files list in backport_pr
+* :ghpull:`3974`: nbconvert: Fix app tests on Window7 w/ Python 3.3
+* :ghpull:`3978`: fix `--existing` with non-localhost IP
+* :ghpull:`3939`: minor checkpoint cleanup
+* :ghpull:`3981`: BF: fix nbconvert rst input prompt spacing
+* :ghpull:`3960`: Don't make sphinx a dependency for importing nbconvert
+* :ghpull:`3973`: logging.Formatter is not new-style in 2.6
+
+Issues (18):
+
+* :ghissue:`4024`: nbconvert markdown issues
+* :ghissue:`4095`: Catch js error in append html in stream/pyerr
+* :ghissue:`4156`: Specifying --gui=tk at the command line
+* :ghissue:`3818`: nbconvert can't handle Heading with Chinese characters on Japanese Windows OS.
+* :ghissue:`4134`: multi-line parser fails on ''' in comment, qtconsole and notebook.
+* :ghissue:`3998`: sample custom.js needs to be updated
+* :ghissue:`4078`: StoreMagic.autorestore not working in 1.0.0
+* :ghissue:`3990`: Buitlin `input` doesn't work over zmq
+* :ghissue:`4015`: nbconvert fails to convert all the content of a notebook
+* :ghissue:`4059`: Issues with Ellipsis literal in Python 3
+* :ghissue:`4103`: Wrong default argument of DirectView.clear
+* :ghissue:`4100`: parallel.client.client references undefined error.EngineError
+* :ghissue:`4005`: IPython.start_kernel doesn't work.
+* :ghissue:`4020`: IPython parallel map fails on numpy arrays
+* :ghissue:`3945`: nbconvert: commandline tests fail Win7x64 Py3.3
+* :ghissue:`3977`: unable to complete remote connections for two-process
+* :ghissue:`3980`: nbconvert rst output lacks needed blank lines
+* :ghissue:`3968`: TypeError: super() argument 1 must be type, not classobj (Python 2.6.6)
+
Issues closed in 1.0
--------------------
View
10 setup.py
@@ -26,12 +26,10 @@
# This check is also made in IPython/__init__, don't forget to update both when
# changing Python version requirements.
-#~ if sys.version[0:3] < '2.6':
- #~ error = """\
-#~ ERROR: 'IPython requires Python Version 2.6 or above.'
-#~ Exiting."""
- #~ print >> sys.stderr, error
- #~ sys.exit(1)
+if sys.version_info[:2] < (2,7):
+ error = "ERROR: IPython requires Python Version 2.7 or above."
+ print(error, file=sys.stderr)
+ sys.exit(1)
PY3 = (sys.version_info[0] >= 3)
View
2  tools/release
@@ -55,6 +55,8 @@ cd(distdir)
print( 'Uploading distribution files...')
for fname in os.listdir('.'):
+ # GitHub doesn't have an API for uploads at the moment
+ continue
print('uploading %s to GitHub' % fname)
desc = "IPython %s source distribution" % version
post_download("ipython/ipython", fname, description=desc)
Something went wrong with that request. Please try again.