[yt-svn] commit/yt: 29 new changesets

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Tue Aug 9 09:14:01 PDT 2016


29 new commits in yt:

https://bitbucket.org/yt_analysis/yt/commits/d47aed80010d/
Changeset:   d47aed80010d
Branch:      yt
User:        xarthisius
Date:        2016-07-18 18:50:25+00:00
Summary:     Update config file handling
Affected #:  9 files

diff -r 0a704f6bd0096052e97d0c338266b7c4d2ea2379 -r d47aed80010dd977422b63190f425c9a2a30de0b doc/source/cookbook/yt_gadget_owls_analysis.ipynb
--- a/doc/source/cookbook/yt_gadget_owls_analysis.ipynb
+++ b/doc/source/cookbook/yt_gadget_owls_analysis.ipynb
@@ -20,7 +20,7 @@
    "source": [
     "The first thing you will need to run these examples is a working installation of yt.  The author or these examples followed the instructions under \"Get yt: from source\" at http://yt-project.org/ to install an up to date development version of yt.\n",
     "\n",
-    "Next you should set the default ``test_data_dir`` in the ``.yt/config`` file in your home directory.  Note that you may have to create the directory and file if it doesn't exist already.\n",
+    "Next you should set the default ``test_data_dir`` in the ``~/.config/yt/ytrc`` file in your home directory.  Note that you may have to create the directory and file if it doesn't exist already.\n",
     "\n",
     "> [yt]\n",
     "\n",

diff -r 0a704f6bd0096052e97d0c338266b7c4d2ea2379 -r d47aed80010dd977422b63190f425c9a2a30de0b doc/source/developing/testing.rst
--- a/doc/source/developing/testing.rst
+++ b/doc/source/developing/testing.rst
@@ -285,7 +285,7 @@
 
 These datasets are available at http://yt-project.org/data/.
 
-Next, modify the file ``~/.yt/config`` to include a section ``[yt]``
+Next, modify the file ``~/.config/yt/ytrc`` to include a section ``[yt]``
 with the parameter ``test_data_dir``.  Set this to point to the
 directory with the test data you want to test with.  Here is an example
 config file:
@@ -313,7 +313,7 @@
 This command will create a set of local answers from the tipsy frontend tests
 and store them in ``$HOME/Documents/test`` (this can but does not have to be the
 same directory as the ``test_data_dir`` configuration variable defined in your
-``.yt/config`` file) in a file named ``local-tipsy``. To run the tipsy
+``~/.config/yt/ytrc`` file) in a file named ``local-tipsy``. To run the tipsy
 frontend's answer tests using a different yt changeset, update to that
 changeset, recompile if necessary, and run the tests using the following
 command:

diff -r 0a704f6bd0096052e97d0c338266b7c4d2ea2379 -r d47aed80010dd977422b63190f425c9a2a30de0b doc/source/faq/index.rst
--- a/doc/source/faq/index.rst
+++ b/doc/source/faq/index.rst
@@ -388,10 +388,10 @@
 To make things easier to load these sample datasets, you can add the parent
 directory to your downloaded sample data to your *yt path*.
 If you set the option ``test_data_dir``, in the section ``[yt]``,
-in ``~/.yt/config``, yt will search this path for them.
+in ``~/.config/yt/ytrc``, yt will search this path for them.
 
 This means you can download these datasets to ``/big_drive/data_for_yt`` , add
-the appropriate item to ``~/.yt/config``, and no matter which directory you are
+the appropriate item to ``~/.config/yt/ytrc``, and no matter which directory you are
 in when running yt, it will also check in *that* directory.
 
 
@@ -437,7 +437,7 @@
 hand, you may want it to output a lot more, since you can't figure out exactly what's going
 wrong, and you want to output some debugging information. The yt log level can be
 changed using the :ref:`configuration-file`, either by setting it in the
-``$HOME/.yt/config`` file:
+``$HOME/.config/yt/ytrc`` file:
 
 .. code-block:: bash
 

diff -r 0a704f6bd0096052e97d0c338266b7c4d2ea2379 -r d47aed80010dd977422b63190f425c9a2a30de0b doc/source/reference/configuration.rst
--- a/doc/source/reference/configuration.rst
+++ b/doc/source/reference/configuration.rst
@@ -18,9 +18,9 @@
 Configuration File Format
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-yt will look for and recognize the file ``$HOME/.yt/config`` as a configuration
+yt will look for and recognize the file ``$HOME/.config/yt/ytrc`` as a configuration
 file, containing several options that can be modified and adjusted to control
-runtime behavior.  For example, a sample ``$HOME/.yt/config`` file could look
+runtime behavior.  For example, a sample ``$HOME/.config/yt/ytrc`` file could look
 like:
 
 .. code-block:: none

diff -r 0a704f6bd0096052e97d0c338266b7c4d2ea2379 -r d47aed80010dd977422b63190f425c9a2a30de0b doc/source/reference/sharing_data.rst
--- a/doc/source/reference/sharing_data.rst
+++ b/doc/source/reference/sharing_data.rst
@@ -36,7 +36,7 @@
 your new password.  You can then receive your API key by clicking on your
 username in the upper left.
 
-After you have gotten your API key, place it in in your ``~/.yt/config`` file:
+After you have gotten your API key, place it in in your ``~/.config/yt/ytrc`` file:
 
 .. code-block:: none
 

diff -r 0a704f6bd0096052e97d0c338266b7c4d2ea2379 -r d47aed80010dd977422b63190f425c9a2a30de0b doc/source/visualizing/sketchfab.rst
--- a/doc/source/visualizing/sketchfab.rst
+++ b/doc/source/visualizing/sketchfab.rst
@@ -105,7 +105,7 @@
 but it requires that you get an API key first.  You can get this API key by
 creating an account and then going to your "dashboard," where it will be listed
 on the right hand side.  Once you've obtained it, put it into your
-``~/.yt/config`` file under the heading ``[yt]`` as the variable
+``~/.config/yt/ytrc`` file under the heading ``[yt]`` as the variable
 ``sketchfab_api_key``.  If you don't want to do this, you can also supply it as
 an argument to the function ``export_sketchfab``.
 

diff -r 0a704f6bd0096052e97d0c338266b7c4d2ea2379 -r d47aed80010dd977422b63190f425c9a2a30de0b setup.py
--- a/setup.py
+++ b/setup.py
@@ -369,6 +369,7 @@
     'amr adaptivemeshrefinement',
     entry_points={'console_scripts': [
         'yt = yt.utilities.command_line:run_main',
+        'yt-config = yt.utilities.configure:main',
     ],
         'nose.plugins.0.10': [
             'answer-testing = yt.utilities.answer_testing.framework:AnswerTesting'

diff -r 0a704f6bd0096052e97d0c338266b7c4d2ea2379 -r d47aed80010dd977422b63190f425c9a2a30de0b yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -67,20 +67,28 @@
     default_colormap = 'arbre',
     ray_tracing_engine = 'embree',
     )
+
+CONFIG_DIR = os.environ.get(
+    'XDG_CONFIG_HOME', os.path.join(os.path.expanduser('~'), '.config', 'yt'))
+if not os.path.exists(CONFIG_DIR):
+    os.makedirs(CONFIG_DIR)
+
+CURRENT_CONFIG_FILE = os.path.join(CONFIG_DIR, 'ytrc')
+__OLD_CONFIG_FILE = os.path.join(os.path.expanduser('~'), '.yt', 'config')
+
 # Here is the upgrade.  We're actually going to parse the file in its entirety
 # here.  Then, if it has any of the Forbidden Sections, it will be rewritten
 # without them.
 
-__fn = os.path.expanduser("~/.yt/config")
-if os.path.exists(__fn):
-    f = open(__fn).read()
+if os.path.exists(__OLD_CONFIG_FILE):
+    f = open(__OLD_CONFIG_FILE).read()
     if any(header in f for header in ["[lagos]","[raven]","[fido]","[enki]"]):
         print("***********************************************************")
         print("* Upgrading configuration file to new format; saving old. *")
         print("***********************************************************")
         # This is of the old format
         cp = configparser.ConfigParser()
-        cp.read(__fn)
+        cp.read(__OLD_CONFIG_FILE)
         # NOTE: To avoid having the 'DEFAULT' section here,
         # we are not passing in ytcfg_defaults to the constructor.
         new_cp = configparser.ConfigParser()
@@ -91,16 +99,25 @@
                 if option.lower() in ytcfg_defaults:
                     new_cp.set("yt", option, cp.get(section, option))
                     print("Setting %s to %s" % (option, cp.get(section, option)))
-        open(__fn + ".old", "w").write(f)
-        new_cp.write(open(__fn, "w"))
-# Pathological check for Kraken
-#elif os.path.exists("~/"):
-#    if not os.path.exists("~/.yt"):
-#            print "yt is creating a new directory, ~/.yt ."
-#            os.mkdir(os.path.exists("~/.yt/"))
-#    # Now we can read in and write out ...
-#    new_cp = configparser.ConfigParser(ytcfg_defaults)
-#    new_cp.write(__fn)
+        open(__OLD_CONFIG_FILE + ".old", "w").write(f)
+        new_cp.write(open(__OLD_CONFIG_FILE, "w"))
+
+    # migrate to new location
+    if not os.path.exists(CURRENT_CONFIG_FILE):
+        print("************************************************")
+        print("* Migrating configuration file to new location *")
+        print("************************************************")
+        cp = configparser.ConfigParser()
+        cp.read([__OLD_CONFIG_FILE])
+        with open(CURRENT_CONFIG_FILE, 'w') as new_cfg:
+            cp.write(new_cfg)
+        os.remove(__OLD_CONFIG_FILE)
+
+if not os.path.exists(CURRENT_CONFIG_FILE):
+    cp = configparser.ConfigParser()
+    cp.add_section("yt")
+    with open(CURRENT_CONFIG_FILE, 'w') as new_cfg:
+        cp.write(new_cfg)
 
 class YTConfigParser(configparser.ConfigParser):
     def __setitem__(self, key, val):
@@ -108,12 +125,8 @@
     def __getitem__(self, key):
         self.get(key[0], key[1])
 
-if os.path.exists(os.path.expanduser("~/.yt/config")):
-    ytcfg = YTConfigParser(ytcfg_defaults)
-    ytcfg.read(['yt.cfg', os.path.expanduser('~/.yt/config')])
-else:
-    ytcfg = YTConfigParser(ytcfg_defaults)
-    ytcfg.read(['yt.cfg'])
+ytcfg = YTConfigParser(ytcfg_defaults)
+ytcfg.read([__OLD_CONFIG_FILE, CURRENT_CONFIG_FILE, 'yt.cfg'])
 if not ytcfg.has_section("yt"):
     ytcfg.add_section("yt")
 

diff -r 0a704f6bd0096052e97d0c338266b7c4d2ea2379 -r d47aed80010dd977422b63190f425c9a2a30de0b yt/utilities/configure.py
--- /dev/null
+++ b/yt/utilities/configure.py
@@ -0,0 +1,78 @@
+# -*- coding: UTF-8 -*-
+#-----------------------------------------------------------------------------
+# Copyright (c) 2016, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+import sys
+import argparse
+from yt.config import CURRENT_CONFIG_FILE
+from yt.extern.six.moves import configparser
+
+CONFIG = configparser.SafeConfigParser()
+CONFIG.read([CURRENT_CONFIG_FILE])
+
+
+def get_config(section, option):
+    return CONFIG.get(section, option)
+
+
+def set_config(section, option, value):
+    if not CONFIG.has_section(section):
+        CONFIG.add_section(section)
+    CONFIG.set(section, option, value)
+    write_config()
+
+
+def write_config(fd=None):
+    if fd is None:
+        with open(CURRENT_CONFIG_FILE, 'w') as fd:
+            CONFIG.write(fd)
+    else:
+        CONFIG.write(fd)
+
+
+def rm_config(section, option):
+    CONFIG.remove_option(section, option)
+    write_config()
+
+
+def main():
+    parser = argparse.ArgumentParser(
+        description='Get and set configuration values for yt')
+    subparsers = parser.add_subparsers(help='sub-command help', dest='cmd')
+
+    get_parser = subparsers.add_parser('get', help='get a config value')
+    set_parser = subparsers.add_parser('set', help='set a config value')
+    rm_parser = subparsers.add_parser('rm', help='remove a config option')
+    subparsers.add_parser('list', help='show all config values')
+
+    get_parser.add_argument(
+        'section', help='The section containing the option.')
+    get_parser.add_argument('option', help='The option to retrieve.')
+
+    set_parser.add_argument(
+        'section', help='The section containing the option.')
+    set_parser.add_argument('option', help='The option to set.')
+    set_parser.add_argument('value', help='The value to set the option to.')
+
+    rm_parser.add_argument(
+        'section', help='The section containing the option to remove.')
+    rm_parser.add_argument('option', help='The option to remove.')
+
+    args = parser.parse_args()
+
+    if args.cmd == 'get':
+        print(get_config(args.section, args.option))
+    elif args.cmd == 'set':
+        set_config(args.section, args.option, args.value)
+    elif args.cmd == 'list':
+        write_config(sys.stdout)
+    elif args.cmd == 'rm':
+        rm_config(args.section, args.option)
+
+if __name__ == '__main__':
+    main()  # pragma: no cover


https://bitbucket.org/yt_analysis/yt/commits/7ffa76607be2/
Changeset:   7ffa76607be2
Branch:      yt
User:        xarthisius
Date:        2016-07-18 19:09:11+00:00
Summary:     Mention and use 'yt-config' in the docs
Affected #:  3 files

diff -r d47aed80010dd977422b63190f425c9a2a30de0b -r 7ffa76607be22c6b07a1e81ed932d41d4a556fe7 doc/source/developing/testing.rst
--- a/doc/source/developing/testing.rst
+++ b/doc/source/developing/testing.rst
@@ -285,15 +285,12 @@
 
 These datasets are available at http://yt-project.org/data/.
 
-Next, modify the file ``~/.config/yt/ytrc`` to include a section ``[yt]``
-with the parameter ``test_data_dir``.  Set this to point to the
-directory with the test data you want to test with.  Here is an example
-config file:
+Next, add the config parameter ``test_data_dir`` pointing to 
+directory with the test data you want to test with, e.g.:
 
 .. code-block:: none
 
-   [yt]
-   test_data_dir = /Users/tomservo/src/yt-data
+   $ yt-config set yt test_data_dir /Users/tomservo/src/yt-data
 
 More data will be added over time.  To run the answer tests, you must first
 generate a set of test answers locally on a "known good" revision, then update

diff -r d47aed80010dd977422b63190f425c9a2a30de0b -r 7ffa76607be22c6b07a1e81ed932d41d4a556fe7 doc/source/faq/index.rst
--- a/doc/source/faq/index.rst
+++ b/doc/source/faq/index.rst
@@ -441,8 +441,7 @@
 
 .. code-block:: bash
 
-   [yt]
-   loglevel = 10 # This sets the log level to "DEBUG"
+   $ yt-config set yt loglevel 10  # This sets the log level to "DEBUG"
 
 which would produce debug (as well as info, warning, and error) messages, or at runtime:
 

diff -r d47aed80010dd977422b63190f425c9a2a30de0b -r 7ffa76607be22c6b07a1e81ed932d41d4a556fe7 doc/source/reference/configuration.rst
--- a/doc/source/reference/configuration.rst
+++ b/doc/source/reference/configuration.rst
@@ -31,7 +31,17 @@
 
 This configuration file would set the logging threshold much lower, enabling
 much more voluminous output from yt.  Additionally, it increases the number of
-datasets tracked between instantiations of yt.
+datasets tracked between instantiations of yt. The configuration file can be
+managed using the ``yt-config`` helper. It can list, add, modify and remove
+options from the configuration file, e.g.:
+
+.. code-block:: none
+
+   $ yt-config -h
+   $ yt-config list
+   $ yt-config set yt loglevel 1
+   $ yt-config rm yt maximumstoreddatasets
+
 
 Configuration Options At Runtime
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


https://bitbucket.org/yt_analysis/yt/commits/acf6156db58a/
Changeset:   acf6156db58a
Branch:      yt
User:        xarthisius
Date:        2016-07-18 19:52:04+00:00
Summary:     Issue warning when old config exists, provide 'yt-config migrate' for convenience
Affected #:  2 files

diff -r 7ffa76607be22c6b07a1e81ed932d41d4a556fe7 -r acf6156db58add2eafab24776a676bcfb72e0286 yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -16,6 +16,7 @@
 #-----------------------------------------------------------------------------
 
 import os
+import warnings
 from yt.extern.six.moves import configparser
 
 ytcfg_defaults = dict(
@@ -102,16 +103,12 @@
         open(__OLD_CONFIG_FILE + ".old", "w").write(f)
         new_cp.write(open(__OLD_CONFIG_FILE, "w"))
 
-    # migrate to new location
-    if not os.path.exists(CURRENT_CONFIG_FILE):
-        print("************************************************")
-        print("* Migrating configuration file to new location *")
-        print("************************************************")
-        cp = configparser.ConfigParser()
-        cp.read([__OLD_CONFIG_FILE])
-        with open(CURRENT_CONFIG_FILE, 'w') as new_cfg:
-            cp.write(new_cfg)
-        os.remove(__OLD_CONFIG_FILE)
+    msg = (
+        "The configuration file {} is deprecated. "
+        "Please migrate your config to {} by running: "
+        "'yt-config migrate'"
+    )
+    warnings.warn(msg.format(__OLD_CONFIG_FILE, CURRENT_CONFIG_FILE))
 
 if not os.path.exists(CURRENT_CONFIG_FILE):
     cp = configparser.ConfigParser()

diff -r 7ffa76607be22c6b07a1e81ed932d41d4a556fe7 -r acf6156db58add2eafab24776a676bcfb72e0286 yt/utilities/configure.py
--- a/yt/utilities/configure.py
+++ b/yt/utilities/configure.py
@@ -7,9 +7,10 @@
 # The full license is in the file COPYING.txt, distributed with this software.
 #-----------------------------------------------------------------------------
 
+import os
 import sys
 import argparse
-from yt.config import CURRENT_CONFIG_FILE
+from yt.config import CURRENT_CONFIG_FILE, __OLD_CONFIG_FILE
 from yt.extern.six.moves import configparser
 
 CONFIG = configparser.SafeConfigParser()
@@ -34,6 +35,21 @@
     else:
         CONFIG.write(fd)
 
+def migrate_config():
+    if not os.path.exists(__OLD_CONFIG_FILE):
+        print("Old config not found.")
+        sys.exit()
+    cp = configparser.ConfigParser()
+    cfgs = [__OLD_CONFIG_FILE]
+    if os.path.exists(CURRENT_CONFIG_FILE):
+        cfgs += CURRENT_CONFIG_FILE
+        
+    cp.read(cfgs)
+    print("Writing new config file to: {}".format(CURRENT_CONFIG_FILE))
+    write_config()
+    print("Removing old config file: {}".format(__OLD_CONFIG_FILE))
+    os.remove(__OLD_CONFIG_FILE)
+
 
 def rm_config(section, option):
     CONFIG.remove_option(section, option)
@@ -48,6 +64,7 @@
     get_parser = subparsers.add_parser('get', help='get a config value')
     set_parser = subparsers.add_parser('set', help='set a config value')
     rm_parser = subparsers.add_parser('rm', help='remove a config option')
+    migrate_parser = subparsers.add_parser('migrate', help='migrate old config file')
     subparsers.add_parser('list', help='show all config values')
 
     get_parser.add_argument(
@@ -71,6 +88,8 @@
         set_config(args.section, args.option, args.value)
     elif args.cmd == 'list':
         write_config(sys.stdout)
+    elif args.cmd == 'migrate':
+        migrate_config()
     elif args.cmd == 'rm':
         rm_config(args.section, args.option)
 


https://bitbucket.org/yt_analysis/yt/commits/bfa4127271a7/
Changeset:   bfa4127271a7
Branch:      yt
User:        xarthisius
Date:        2016-07-18 20:08:44+00:00
Summary:     Fix logic in 'migrate'
Affected #:  1 file

diff -r acf6156db58add2eafab24776a676bcfb72e0286 -r bfa4127271a7406a8cbea1f095967292d33a45b9 yt/utilities/configure.py
--- a/yt/utilities/configure.py
+++ b/yt/utilities/configure.py
@@ -39,12 +39,7 @@
     if not os.path.exists(__OLD_CONFIG_FILE):
         print("Old config not found.")
         sys.exit()
-    cp = configparser.ConfigParser()
-    cfgs = [__OLD_CONFIG_FILE]
-    if os.path.exists(CURRENT_CONFIG_FILE):
-        cfgs += CURRENT_CONFIG_FILE
-        
-    cp.read(cfgs)
+    CONFIG.read(__OLD_CONFIG_FILE)
     print("Writing new config file to: {}".format(CURRENT_CONFIG_FILE))
     write_config()
     print("Removing old config file: {}".format(__OLD_CONFIG_FILE))


https://bitbucket.org/yt_analysis/yt/commits/1e314c453cfb/
Changeset:   1e314c453cfb
Branch:      yt
User:        xarthisius
Date:        2016-07-19 00:08:01+00:00
Summary:     fix pep8
Affected #:  1 file

diff -r bfa4127271a7406a8cbea1f095967292d33a45b9 -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a yt/utilities/configure.py
--- a/yt/utilities/configure.py
+++ b/yt/utilities/configure.py
@@ -59,7 +59,7 @@
     get_parser = subparsers.add_parser('get', help='get a config value')
     set_parser = subparsers.add_parser('set', help='set a config value')
     rm_parser = subparsers.add_parser('rm', help='remove a config option')
-    migrate_parser = subparsers.add_parser('migrate', help='migrate old config file')
+    subparsers.add_parser('migrate', help='migrate old config file')
     subparsers.add_parser('list', help='show all config values')
 
     get_parser.add_argument(


https://bitbucket.org/yt_analysis/yt/commits/201762075009/
Changeset:   201762075009
Branch:      yt
User:        xarthisius
Date:        2016-07-19 14:13:55+00:00
Summary:     merging
Affected #:  23 files

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/analyzing/analysis_modules/halo_catalogs.rst
--- a/doc/source/analyzing/analysis_modules/halo_catalogs.rst
+++ b/doc/source/analyzing/analysis_modules/halo_catalogs.rst
@@ -121,8 +121,8 @@
 allows for robust (grid-independent, shape-independent, and noise-
 resilient) tracking of substructure. The code is prepackaged with yt,
 but also `separately available <https://bitbucket.org/gfcstanford/rockstar>`_. The lead
-developer is Peter Behroozi, and the methods are described in `Behroozi
-et al. 2011 <http://arxiv.org/abs/1110.4372>`_.
+developer is Peter Behroozi, and the methods are described in
+`Behroozi et al. 2011 <http://adsabs.harvard.edu/abs/2011arXiv1110.4372B>`_.
 In order to run the Rockstar halo finder in yt, make sure you've
 :ref:`installed it so that it can integrate with yt <rockstar-installation>`.
 
@@ -192,6 +192,8 @@
 Inside the ``outbase`` directory there is a text file named ``datasets.txt``
 that records the connection between ds names and the Rockstar file names.
 
+.. _rockstar-installation:
+
 Installing Rockstar
 """""""""""""""""""
 

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/analyzing/analysis_modules/photon_simulator.rst
--- a/doc/source/analyzing/analysis_modules/photon_simulator.rst
+++ b/doc/source/analyzing/analysis_modules/photon_simulator.rst
@@ -99,9 +99,9 @@
    To work out the following examples, you should install
    `AtomDB <http://www.atomdb.org>`_ and get the files from the
    `xray_data <http://yt-project.org/data/xray_data.tar.gz>`_ auxiliary
-   data package (see the ``xray_data`` `README <xray_data_README.html>`_
-   for details on the latter). Make sure that in what follows you
-   specify the full path to the locations of these files.
+   data package (see the :ref:`xray_data_README` for details on the latter). 
+   Make sure that in what follows you specify the full path to the locations 
+   of these files.
 
 To generate photons from this dataset, we have several different things
 we need to set up. The first is a standard yt data object. It could

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/analyzing/analysis_modules/radial_column_density.rst
--- a/doc/source/analyzing/analysis_modules/radial_column_density.rst
+++ /dev/null
@@ -1,93 +0,0 @@
-.. _radial-column-density:
-
-Radial Column Density
-=====================
-.. sectionauthor:: Stephen Skory <s at skory.us>
-.. versionadded:: 2.3
-
-.. note::
-
-    As of :code:`yt-3.0`, the radial column density analysis module is not
-    currently functional.  This functionality is still available in
-    :code:`yt-2.x`.  If you would like to use these features in :code:`yt-3.x`,
-    help is needed to port them over.  Contact the yt-users mailing list if you
-    are interested in doing this.
-
-This module allows the calculation of column densities around a point over a
-field such as ``NumberDensity`` or ``Density``.
-This uses :ref:`healpix_volume_rendering` to interpolate column densities
-on the grid cells.
-
-Details
--------
-
-This module allows the calculation of column densities around a single point.
-For example, this is useful for looking at the gas around a radiating source.
-Briefly summarized, the calculation is performed by first creating a number
-of HEALPix shells around the central point.
-Next, the value of the column density at cell centers is found by
-linearly interpolating the values on the inner and outer shell.
-This is added as derived field, which can be used like any other derived field.
-
-Basic Example
--------------
-
-In this simple example below, the radial column density for the field
-``NumberDensity`` is calculated and added as a derived field named
-``RCDNumberDensity``.
-The calculations will use the starting point of (x, y, z) = (0.5, 0.5, 0.5) and
-go out to a maximum radius of 0.5 in code units.
-Due to the way normalization is handled in HEALPix, the column density
-calculation can extend out only as far as the nearest face of the volume.
-For example, with a center point of (0.2, 0.3, 0.4), the column density
-is calculated out to only a radius of 0.2.
-The column density will be output as zero (0.0) outside the maximum radius.
-Just like a real number column density, when the derived is added using
-``add_field``, we give the units as :math:`1/\rm{cm}^2`.
-
-.. code-block:: python
-
-  from yt.mods import *
-  from yt.analysis_modules.radial_column_density.api import *
-  ds = load("data0030")
-
-  rcdnumdens = RadialColumnDensity(ds, 'NumberDensity', [0.5, 0.5, 0.5],
-    max_radius = 0.5)
-  def _RCDNumberDensity(field, data, rcd = rcdnumdens):
-      return rcd._build_derived_field(data)
-  add_field('RCDNumberDensity', _RCDNumberDensity, units=r'1/\rm{cm}^2')
-
-  dd = ds.all_data()
-  print(dd['RCDNumberDensity'])
-
-The field ``RCDNumberDensity`` can be used just like any other derived field
-in yt.
-
-Additional Parameters
----------------------
-
-Each of these parameters is added to the call to ``RadialColumnDensity()``,
-just like ``max_radius`` is used above.
-
-  * ``steps`` : integer - Because this implementation uses linear
-    interpolation to calculate the column
-    density at each cell, the accuracy of the solution goes up as the number of
-    HEALPix surfaces is increased.
-    The ``steps`` parameter controls the number of HEALPix surfaces, and a larger
-    number is more accurate, but slower. Default = 10.
-
-  * ``base`` : string - This controls where the surfaces are placed, with
-    linear "lin" or logarithmic "log" spacing. The inner-most
-    surface is always set to the size of the smallest cell.
-    Default = "lin".
-
-  * ``Nside`` : int
-    The resolution of column density calculation as performed by
-    HEALPix. Higher numbers mean higher quality. Max = 8192.
-    Default = 32.
-
-  * ``ang_divs`` : imaginary integer
-    This number controls the gridding of the HEALPix projection onto
-    the spherical surfaces. Higher numbers mean higher quality.
-    Default = 800j.
-

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/analyzing/analysis_modules/xray_data_README.rst
--- a/doc/source/analyzing/analysis_modules/xray_data_README.rst
+++ b/doc/source/analyzing/analysis_modules/xray_data_README.rst
@@ -1,3 +1,5 @@
+.. _xray_data_README:
+
 Auxiliary Data Files for use with yt's Photon Simulator
 =======================================================
 

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/analyzing/parallel_computation.rst
--- a/doc/source/analyzing/parallel_computation.rst
+++ b/doc/source/analyzing/parallel_computation.rst
@@ -21,7 +21,7 @@
 * Derived Quantities (total mass, angular momentum, etc) (:ref:`creating_derived_quantities`,
   :ref:`derived-quantities`)
 * 1-, 2-, and 3-D profiles (:ref:`generating-profiles-and-histograms`)
-* Halo finding (:ref:`halo_finding`)
+* Halo analysis (:ref:`halo-analysis`)
 * Volume rendering (:ref:`volume_rendering`)
 * Isocontours & flux calculations (:ref:`extracting-isocontour-information`)
 
@@ -194,7 +194,7 @@
 
 The following operations use spatial decomposition:
 
-* :ref:`halo_finding`
+* :ref:`halo-analysis`
 * :ref:`volume_rendering`
 
 Grid Decomposition
@@ -501,7 +501,7 @@
 subtle art in estimating the amount of memory needed for halo finding, but a
 rule of thumb is that the HOP halo finder is the most memory intensive
 (:func:`HaloFinder`), and Friends of Friends (:func:`FOFHaloFinder`) being the
-most memory-conservative. For more information, see :ref:`halo_finding`.
+most memory-conservative. For more information, see :ref:`halo-analysis`.
 
 **Volume Rendering**
 

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/analyzing/saving_data.rst
--- a/doc/source/analyzing/saving_data.rst
+++ b/doc/source/analyzing/saving_data.rst
@@ -1,4 +1,4 @@
-.. _saving_data
+.. _saving_data:
 
 Saving Reloadable Data
 ======================

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/cookbook/cosmological_analysis.rst
--- a/doc/source/cookbook/cosmological_analysis.rst
+++ b/doc/source/cookbook/cosmological_analysis.rst
@@ -65,10 +65,13 @@
 
 .. yt_cookbook:: light_ray.py
 
+.. _cookbook-single-dataset-light-ray:
+
+Single Dataset Light Ray
+~~~~~~~~~~~~~~~~~~~~~~~~
+
 This script demonstrates how to make a light ray from a single dataset.
 
-.. _cookbook-single-dataset-light-ray:
-
 .. yt_cookbook:: single_dataset_light_ray.py
 
 Creating and Fitting Absorption Spectra

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/developing/building_the_docs.rst
--- a/doc/source/developing/building_the_docs.rst
+++ b/doc/source/developing/building_the_docs.rst
@@ -176,6 +176,7 @@
 .. _Sphinx: http://sphinx-doc.org/
 .. _pandoc: http://johnmacfarlane.net/pandoc/
 .. _ffmpeg: http://www.ffmpeg.org/
+.. _IPython: https://ipython.org/
 
 You will also need the full yt suite of `yt test data
 <http://yt-project.org/data/>`_, including the larger datasets that are not used

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/developing/extensions.rst
--- a/doc/source/developing/extensions.rst
+++ b/doc/source/developing/extensions.rst
@@ -3,7 +3,7 @@
 Extension Packages
 ==================
 
-.. note:: For some additional discussion, see :ref:`YTEP-0029
+.. note:: For some additional discussion, see `YTEP-0029
           <http://ytep.readthedocs.io/en/latest/YTEPs/YTEP-0029.html>`_, where
           this plan was designed.
 

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/developing/testing.rst
--- a/doc/source/developing/testing.rst
+++ b/doc/source/developing/testing.rst
@@ -103,7 +103,7 @@
    accept no arguments. The test function should do some work that tests some
    functionality and should also verify that the results are correct using
    assert statements or functions.  
-# Tests can ``yield`` a tuple of the form ``function``, ``argument_one``,
+#. Tests can ``yield`` a tuple of the form ``function``, ``argument_one``,
    ``argument_two``, etc.  For example ``yield assert_equal, 1.0, 1.0`` would be
    captured by nose as a test that asserts that 1.0 is equal to 1.0.
 #. Use ``fake_random_ds`` to test on datasets, and be sure to test for
@@ -484,7 +484,7 @@
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 Before any code is added to or modified in the yt codebase, each incoming
 changeset is run against all available unit and answer tests on our `continuous
-integration server <http://tests.yt-project.org>`_. While unit tests are
+integration server <https://tests.yt-project.org>`_. While unit tests are
 autodiscovered by `nose <http://nose.readthedocs.org/en/latest/>`_ itself,
 answer tests require definition of which set of tests constitute to a given
 answer. Configuration for the integration server is stored in

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/intro/index.rst
--- a/doc/source/intro/index.rst
+++ b/doc/source/intro/index.rst
@@ -105,7 +105,7 @@
 use external libraries or codes.  While they are installed with yt, they are
 not loaded by default in every session so you have to call them specifically.
 Examples include :ref:`halo analysis <halo-analysis>` (including
-:ref:`halo finding <halo_finding>`, :ref:`merger trees <merger_tree>`,
+:ref:`halo finding <halo-analysis>`, :ref:`merger trees <merger_tree>`,
 :ref:`halo mass functions <halo_mass_function>`), :ref:`synthetic observations
 <synthetic-observations>` (including :ref:`cosmological light cones
 <light-cone-generator>`, :ref:`cosmological light rays <light-ray-generator>`,

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/reference/changelog.rst
--- a/doc/source/reference/changelog.rst
+++ b/doc/source/reference/changelog.rst
@@ -611,7 +611,7 @@
  * WebGL interface for isocontours and a pannable map widget added to Reason
  * Performance improvements for volume rendering
  * Adaptive HEALPix support
- * Column density calculations (see :ref:`radial-column-density`)
+ * Column density calculations
  * Massive speedup for 1D profiles
  * Lots more, bug fixes etc.
  * Substantial improvements to the documentation, including
@@ -733,9 +733,9 @@
 -----------
 
 Version 1.6 is a point release, primarily notable for the new parallel halo
-finder (see :ref:`halo_finding`)
+finder (see :ref:`halo-analysis`)
 
- * (New) Parallel HOP ( http://arxiv.org/abs/1001.3411 , :ref:`halo_finding` )
+ * (New) Parallel HOP ( http://arxiv.org/abs/1001.3411 , :ref:`halo-analysis` )
  * (Beta) Software ray casting and volume rendering
    (see :ref:`volume_rendering`)
  * Rewritten, faster and better contouring engine for clump identification

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/reference/sharing_data.rst
--- a/doc/source/reference/sharing_data.rst
+++ /dev/null
@@ -1,108 +0,0 @@
-What is the yt Hub?
-===================
-
-.. warning:: The yt Hub is currently offline due to some hosting problems.  We
-             hope to have it back up online soon.
-
-The yt data hub is a mechanism by which images, data objects and projects can be
-shared with other people.  For instance, one can upload projections and browse
-them with an interface similar to Google Maps or upload notebooks and view them
-from any web browser.
-
-.. note:: All items posted on the hub are public!
-
-Over time, more widgets will be added, and more datatypes will be able to be
-uploaded.  If you are interested in adding more ways of sharing data, please
-email the developers' list.  We would like to add support for 3D widgets such
-as isocontours as well as interactive binning and rebinning of data from yt
-data objects, to be displayed as phase plots and profiles.
-
-Registering a User
-------------------
-
-Because of problems with spammers, registering a user can only be done from the
-yt command line.  Once you have registered a user, you can log on to the
-website and obtain an API key.
-
-To register a user:
-
-.. code-block:: bash
-
-   $ yt hub_register
-
-This will walk you through the process of registering.  You will need to supply
-a name, a username, a password and an email address.  Once you have gotten that
-out of the way, you can go to http://hub.yt-project.org/login and log in with
-your new password.  You can then receive your API key by clicking on your
-username in the upper left.
-
-After you have gotten your API key, place it in in your ``~/.config/yt/ytrc`` file:
-
-.. code-block:: none
-
-   [yt]
-   hub_api_key = 3fd8de56c2884c13a2de4dd51a80974b
-
-Replace ``3fd8de56c2884c13a2de4dd51a80974b`` with your API key.  At this point,
-you're ready to go!
-
-What Can Be Uploaded
---------------------
-
-Currently, the yt hub can accept these types of data:
-
- * Projects and script repositories: these will be displayed with an optional
-   image, a description, and a link to the source repository.
- * Projections and Slices: these will be displayed in a maps-like interface,
-   for interactive panning and zooming
- * IPython notebooks: these are stored on the hub and are made available for
-   download and via the IPython `nbviewer <http://nbviewer.ipython.org/>`_
-   service.
-
-How to Upload Data
-------------------
-
-Uploading data takes place inside scripts.  For the most part, it is relatively
-simple to do: you construct the object you would like to share, and then you
-upload it.
-
-Uploading Projects
-~~~~~~~~~~~~~~~~~~
-
-For information on how to share a project or a set of scripts, see
-:ref:`share-your-scripts`.
-
-Uploading Projections and Slices
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Projections and slices both have a ``hub_upload`` method.  Here is an example
-of uploading a projection:
-
-.. code-block:: python
-
-   from yt.mods import *
-   ds = load("IsolatedGalaxy/galaxy0030/galaxy0030")
-   proj = ds.proj(0, "density", weight="density")
-   proj.hub_upload()
-
-Here is an example of uploading a slice:
-
-.. code-block:: python
-
-   from yt.mods import *
-   ds = load("JHK-DD0030/galaxy0030")
-   sl = ds.slice(0, 0.5, fields=["density"])
-   sl.hub_upload()
-
-Uploading Notebooks
-~~~~~~~~~~~~~~~~~~~
-
-Notebooks can be uploaded from the bash command line:
-
-.. code-block:: bash
-
-   yt upload_notebook notebook_file.ipynb
-
-After the notebook is finished uploading, yt will print a link to the raw
-notebook as well as an nbviewer link to the same notebook.  Your notebooks will
-be stored under your hub profile.

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/visualizing/plots.rst
--- a/doc/source/visualizing/plots.rst
+++ b/doc/source/visualizing/plots.rst
@@ -301,7 +301,7 @@
 Off Axis Projection Plots
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Internally, off axis projections are created using :ref:`the-camera-interface`
+Internally, off axis projections are created using :ref:`camera`
 by applying the
 :class:`~yt.visualization.volume_rendering.transfer_functions.ProjectionTransferFunction`.
 In this use case, the volume renderer casts a set of plane parallel rays, one

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 doc/source/yt3differences.rst
--- a/doc/source/yt3differences.rst
+++ b/doc/source/yt3differences.rst
@@ -193,7 +193,7 @@
 than using ``from yt.mods import *``, we suggest using ``import yt`` in new
 scripts.  Most commonly used yt functionality is attached to the ``yt`` module.
 Load a dataset with ``yt.load()``, create a phase plot using ``yt.PhasePlot``,
-and much more, see :ref:`the api docs api-reference` to learn more about what's
+and much more, see :ref:`the api docs <api-reference>` to learn more about what's
 in the ``yt`` namespace, or just use tab completion in IPython: ``yt.<tab>``.
 
 It's still possible to use ``from yt.mods import *`` to create an interactive

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 yt/analysis_modules/halo_analysis/halo_catalog.py
--- a/yt/analysis_modules/halo_analysis/halo_catalog.py
+++ b/yt/analysis_modules/halo_analysis/halo_catalog.py
@@ -267,8 +267,11 @@
         and/or filters called in succession.  Recipes can be used to store a more
         complex series of analysis tasks as a single entity.
 
+        Currently, the available recipe is ``calculate_virial_quantities``.
+
         Parameters
         ----------
+
         halo_recipe : string
             The name of the recipe.
 
@@ -290,10 +293,6 @@
         >>>
         >>> hc.create()
 
-        Available Recipes
-        -----------------
-        calculate_virial_quantities
-
         """
 
         halo_recipe = recipe_registry.find(recipe, *args, **kwargs)

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 yt/analysis_modules/halo_analysis/halo_recipes.py
--- a/yt/analysis_modules/halo_analysis/halo_recipes.py
+++ b/yt/analysis_modules/halo_analysis/halo_recipes.py
@@ -46,8 +46,7 @@
     Calculate virial quantities with the following procedure:
     1. Create a sphere data container.
     2. Create 1D radial profiles of overdensity and any requested fields.
-    3. Call virial_quantities callback to interpolate profiles for
-       value of critical overdensity.
+    3. Call virial_quantities callback to interpolate profiles for value of critical overdensity.
     4. Delete profile and sphere objects from halo.
 
     Parameters

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 yt/data_objects/derived_quantities.py
--- a/yt/data_objects/derived_quantities.py
+++ b/yt/data_objects/derived_quantities.py
@@ -114,9 +114,10 @@
 
     Parameters
     ----------
-    fields : field or list of fields
+
+    fields : string / tuple, or list of strings / tuples
         The field or fields of which the average value is to be calculated.
-    weight : field
+    weight : string or tuple
         The weight field.
 
     Examples
@@ -358,10 +359,10 @@
 
     Parameters
     ----------
-    fields : field or list of fields
-        The field or fields of which the variance and mean values are
-        to be calculated.
-    weight : field
+
+    fields : string / tuple, or list of strings / tuples
+        The field or fields of which the average value is to be calculated.
+    weight : string or tuple
         The weight field.
 
     Examples
@@ -535,7 +536,7 @@
 
     Parameters
     ----------
-    field : field
+    field : tuple or string
         The field over which the extrema are to be calculated.
     sample_fields : list of fields
         The fields to sample and return at the minimum value.
@@ -582,7 +583,8 @@
 
     Parameters
     ----------
-    field : field
+
+    field : tuple or string
         The field over which the extrema are to be calculated.
 
     Examples
@@ -608,7 +610,7 @@
 
     Parameters
     ----------
-    field : field
+    field : tuple or string
         The field over which the extrema are to be calculated.
     sample_fields : list of fields
         The fields to sample and return at the minimum value.
@@ -631,7 +633,8 @@
 
     Parameters
     ----------
-    field : field
+
+    field : tuple or string
         The field over which the extrema are to be calculated.
 
     Examples

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 yt/frontends/flash/data_structures.py
--- a/yt/frontends/flash/data_structures.py
+++ b/yt/frontends/flash/data_structures.py
@@ -384,6 +384,9 @@
         elif self.dimensionality < 3 and self.geometry == "spherical":
             mylog.warning("Extending phi dimension to 2PI + left edge.")
             self.domain_right_edge[2] = self.domain_left_edge[2] + 2*np.pi
+        if self.dimensionality == 1 and self.geometry == "spherical":
+            mylog.warning("Extending theta dimension to PI + left edge.")
+            self.domain_right_edge[1] = self.domain_left_edge[1] + np.pi
         self.domain_dimensions = \
             np.array([nblockx*nxb,nblocky*nyb,nblockz*nzb])
 

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 yt/frontends/gdf/data_structures.py
--- a/yt/frontends/gdf/data_structures.py
+++ b/yt/frontends/gdf/data_structures.py
@@ -89,7 +89,6 @@
         h5f = h5py.File(self.index_filename, 'r')
         self.dataset_type = dataset_type
         GridIndex.__init__(self, ds, dataset_type)
-        self.max_level = 10  # FIXME
         self.directory = os.path.dirname(self.index_filename)
         h5f.close()
 

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 yt/visualization/plot_container.py
--- a/yt/visualization/plot_container.py
+++ b/yt/visualization/plot_container.py
@@ -428,33 +428,36 @@
     @invalidate_plot
     @invalidate_figure
     def set_font(self, font_dict=None):
-        """set the font and font properties
+        """
+
+        Set the font and font properties.
 
         Parameters
         ----------
 
         font_dict : dict
-          A dict of keyword parameters to be passed to
-          :py:class:`matplotlib.font_manager.FontProperties`.
+            A dict of keyword parameters to be passed to 
+            :class:`matplotlib.font_manager.FontProperties`.
 
-          Possible keys include
-          * family - The font family. Can be serif, sans-serif, cursive,
-            'fantasy' or 'monospace'.
-          * style - The font style. Either normal, italic or oblique.
-          * color - A valid color string like 'r', 'g', 'red', 'cobalt', and
-            'orange'.
-          * variant: Either normal or small-caps.
-          * size: Either an relative value of xx-small, x-small, small, medium,
-            large, x-large, xx-large or an absolute font size, e.g. 12
-          * stretch: A numeric value in the range 0-1000 or one of
-            ultra-condensed, extra-condensed, condensed, semi-condensed, normal,
-            semi-expanded, expanded, extra-expanded or ultra-expanded
-          * weight: A numeric value in the range 0-1000 or one of ultralight,
-            light, normal, regular, book, medium, roman, semibold, demibold, 
-            demi, bold, heavy, extra bold, or black
+            Possible keys include:
 
-          See the matplotlib font manager API documentation for more details.
-          http://matplotlib.org/api/font_manager_api.html
+            * family - The font family. Can be serif, sans-serif, cursive,
+              'fantasy' or 'monospace'.
+            * style - The font style. Either normal, italic or oblique.
+            * color - A valid color string like 'r', 'g', 'red', 'cobalt',
+              and 'orange'.
+            * variant - Either normal or small-caps.
+            * size - Either a relative value of xx-small, x-small, small,
+              medium, large, x-large, xx-large or an absolute font size, e.g. 12
+            * stretch - A numeric value in the range 0-1000 or one of
+              ultra-condensed, extra-condensed, condensed, semi-condensed,
+              normal, semi-expanded, expanded, extra-expanded or ultra-expanded
+            * weight - A numeric value in the range 0-1000 or one of ultralight,
+              light, normal, regular, book, medium, roman, semibold, demibold,
+              demi, bold, heavy, extra bold, or black
+
+            See the matplotlib font manager API documentation for more details.
+            http://matplotlib.org/api/font_manager_api.html
 
         Notes
         -----
@@ -469,7 +472,7 @@
 
         >>> slc = SlicePlot(ds, 'x', 'Density')
         >>> slc.set_font({'family':'sans-serif', 'style':'italic',
-                          'weight':'bold', 'size':24, 'color':'blue'})
+        ...               'weight':'bold', 'size':24, 'color':'blue'})
 
         """
         from matplotlib.font_manager import FontProperties

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 yt/visualization/plot_modifications.py
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -1852,22 +1852,19 @@
 
             "plot" -- the 2D coordinates defined by the actual plot limits
 
-            "axis" -- the MPL axis coordinates: (0,0) is lower left; (1,1) is
-                      upper right
+            "axis" -- the MPL axis coordinates: (0,0) is lower left; (1,1) is upper right
 
-            "figure" -- the MPL figure coordinates: (0,0) is lower left, (1,1)
-                        is upper right
+            "figure" -- the MPL figure coordinates: (0,0) is lower left, (1,1) is upper right
 
     text_args : dictionary, optional
         A dictionary of any arbitrary parameters to be passed to the Matplotlib
-        text object.  Defaults: {'color':'white',
-        'horizontalalignment':'center', 'verticalalignment':'top'}.
+        text object.  Defaults: ``{'color':'white',
+        'horizontalalignment':'center', 'verticalalignment':'top'}``.
 
     inset_box_args : dictionary, optional
         A dictionary of any arbitrary parameters to be passed to the Matplotlib
         FancyBboxPatch object as the inset box around the text.
-        Defaults: {'boxstyle':'square,pad=0.3', 'facecolor':'black',
-                  'linewidth':3, 'edgecolor':'white', 'alpha':0.5}
+        Defaults: ``{'boxstyle':'square', 'pad':0.3, 'facecolor':'black', 'linewidth':3, 'edgecolor':'white', 'alpha':0.5}``
 
     Example
     -------
@@ -2028,22 +2025,20 @@
 
             "plot" -- the 2D coordinates defined by the actual plot limits
 
-            "axis" -- the MPL axis coordinates: (0,0) is lower left; (1,1) is
-                      upper right
+            "axis" -- the MPL axis coordinates: (0,0) is lower left; (1,1) is upper right
 
-            "figure" -- the MPL figure coordinates: (0,0) is lower left, (1,1)
-                        is upper right
+            "figure" -- the MPL figure coordinates: (0,0) is lower left, (1,1) is upper right
 
     text_args : dictionary, optional
         A dictionary of parameters to used to update the font_properties
         for the text in this callback.  For any property not set, it will
         use the defaults of the plot.  Thus one can modify the text size with:
-        text_args={'size':24}
+        ``text_args={'size':24}``
 
     size_bar_args : dictionary, optional
         A dictionary of parameters to be passed to the Matplotlib
         AnchoredSizeBar initializer.
-        Defaults: {'pad': 0.25, 'sep': 5, 'borderpad': 1, 'color': 'w'}
+        Defaults: ``{'pad': 0.25, 'sep': 5, 'borderpad': 1, 'color': 'w'}``
 
     draw_inset_box : boolean, optional
         Whether or not an inset box should be included around the scale bar.
@@ -2051,8 +2046,7 @@
     inset_box_args : dictionary, optional
         A dictionary of keyword arguments to be passed to the matplotlib Patch
         object that represents the inset box.
-        Defaults: {'facecolor': 'black', 'linewidth': 3, 'edgecolor', 'white',
-                   'alpha': 0.5, 'boxstyle': 'square'}
+        Defaults: ``{'facecolor': 'black', 'linewidth': 3, 'edgecolor': 'white', 'alpha': 0.5, 'boxstyle': 'square'}``
 
 
     Example

diff -r 1e314c453cfb2f5f63a6e0e28578416c5bafdd2a -r 201762075009e25eb2bebdd3e006300a6c6dd888 yt/visualization/profile_plotter.py
--- a/yt/visualization/profile_plotter.py
+++ b/yt/visualization/profile_plotter.py
@@ -1071,45 +1071,51 @@
 
     @invalidate_plot
     def set_font(self, font_dict=None):
-        """set the font and font properties
+        """
+
+        Set the font and font properties.
 
         Parameters
         ----------
+
         font_dict : dict
-        A dict of keyword parameters to be passed to
-        :py:class:`matplotlib.font_manager.FontProperties`.
+            A dict of keyword parameters to be passed to 
+            :class:`matplotlib.font_manager.FontProperties`.
 
-        Possible keys include
-        * family - The font family. Can be serif, sans-serif, cursive, 'fantasy' or
-          'monospace'.
-        * style - The font style. Either normal, italic or oblique.
-        * color - A valid color string like 'r', 'g', 'red', 'cobalt', and
-          'orange'.
-        * variant: Either normal or small-caps.
-        * size: Either an relative value of xx-small, x-small, small, medium,
-          large, x-large, xx-large or an absolute font size, e.g. 12
-        * stretch: A numeric value in the range 0-1000 or one of
-          ultra-condensed, extra-condensed, condensed, semi-condensed, normal,
-          semi-expanded, expanded, extra-expanded or ultra-expanded
-        * weight: A numeric value in the range 0-1000 or one of ultralight,
-          light, normal, regular, book, medium, roman, semibold, demibold, demi,
-          bold, heavy, extra bold, or black
+            Possible keys include:
 
-        See the matplotlib font manager API documentation for more details.
-        http://matplotlib.org/api/font_manager_api.html
+            * family - The font family. Can be serif, sans-serif, cursive,
+              'fantasy', or 'monospace'.
+            * style - The font style. Either normal, italic or oblique.
+            * color - A valid color string like 'r', 'g', 'red', 'cobalt', 
+              and 'orange'.
+            * variant - Either normal or small-caps.
+            * size - Either a relative value of xx-small, x-small, small, 
+              medium, large, x-large, xx-large or an absolute font size, e.g. 12
+            * stretch - A numeric value in the range 0-1000 or one of
+              ultra-condensed, extra-condensed, condensed, semi-condensed,
+              normal, semi-expanded, expanded, extra-expanded or ultra-expanded
+            * weight - A numeric value in the range 0-1000 or one of ultralight,
+              light, normal, regular, book, medium, roman, semibold, demibold,
+              demi, bold, heavy, extra bold, or black
+
+            See the matplotlib font manager API documentation for more details.
+            http://matplotlib.org/api/font_manager_api.html
 
         Notes
         -----
+
         Mathtext axis labels will only obey the `size` and `color` keyword.
 
         Examples
         --------
+
         This sets the font to be 24-pt, blue, sans-serif, italic, and
         bold-face.
 
         >>> prof = ProfilePlot(ds.all_data(), 'density', 'temperature')
         >>> slc.set_font({'family':'sans-serif', 'style':'italic',
-                          'weight':'bold', 'size':24, 'color':'blue'})
+        ...               'weight':'bold', 'size':24, 'color':'blue'})
 
         """
         from matplotlib.font_manager import FontProperties


https://bitbucket.org/yt_analysis/yt/commits/33e98387a021/
Changeset:   33e98387a021
Branch:      yt
User:        xarthisius
Date:        2016-07-19 14:27:53+00:00
Summary:     update hub_register
Affected #:  1 file

diff -r 201762075009e25eb2bebdd3e006300a6c6dd888 -r 33e98387a02196c47cd679082abe8209af03311c yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -26,7 +26,7 @@
 import json
 import pprint
 
-from yt.config import ytcfg
+from yt.config import ytcfg, CURRENT_CONFIG_FILE
 ytcfg["yt","__command_line"] = "True"
 from yt.startup_tasks import parser, subparsers
 from yt.funcs import \
@@ -44,6 +44,7 @@
     SlicePlot, \
     ProjectionPlot
 from yt.utilities.metadata import get_metadata
+from yt.utilities.configure import set_config
 from yt.utilities.exceptions import \
     YTOutputNotIdentified, YTFieldNotParseable
 
@@ -560,22 +561,23 @@
     name = "hub_register"
     description = \
         """
-        Register a user on the Hub: http://hub.yt-project.org/
+        Register a user on the Hub: http://hub.yt/
         """
     def __call__(self, args):
-        # We need these pieces of information:
-        #   1. Name
-        #   2. Email
-        #   3. Username
-        #   4. Password (and password2)
-        #   5. (optional) URL
-        #   6. "Secret" key to make it epsilon harder for spammers
-        if ytcfg.get("yt","hub_api_key") != "":
+        try:
+            import requests
+        except ImportError:
+            print("yt {} requires requests to be installed".format(self.name))
+            print("Please install them using you python package manager, e.g.:")
+            print("   pip install requests --user")
+            exit()
+        if ytcfg.get("yt", "hub_api_key") != "":
             print("You seem to already have an API key for the hub in")
-            print("~/.yt/config .  Delete this if you want to force a")
+            print("{} . Delete this if you want to force a".format(CURRENT_CONFIG_FILE))
             print("new user registration.")
+            exit()
         print("Awesome!  Let's start by registering a new user for you.")
-        print("Here's the URL, for reference: http://hub.yt-project.org/ ")
+        print("Here's the URL, for reference: http://hub.yt/ ")
         print()
         print("As always, bail out with Ctrl-C at any time.")
         print()
@@ -586,8 +588,11 @@
         print()
         print("To start out, what's your name?")
         print()
-        name = input("Name? ")
-        if len(name) == 0: sys.exit(1)
+        first_name = input("First Name? ")
+        if len(first_name) == 0: sys.exit(1)
+        print()
+        last_name = input("Last Name? ")
+        if len(last_name) == 0: sys.exit(1)
         print()
         print("And your email address?")
         print()
@@ -604,33 +609,32 @@
             print("Sorry, they didn't match!  Let's try again.")
             print()
         print()
-        print("Would you like a URL displayed for your user?")
-        print("Leave blank if no.")
-        print()
-        url = input("URL? ")
-        print()
         print("Okay, press enter to register.  You should receive a welcome")
         print("message at %s when this is complete." % email)
         print()
         input()
-        data = dict(name = name, email = email, username = username,
-                    password = password1, password2 = password2,
-                    url = url, zap = "rowsdower")
-        data = urllib.parse.urlencode(data)
-        hub_url = "https://hub.yt-project.org/create_user"
-        req = urllib.request.Request(hub_url, data)
-        try:
-            urllib.request.urlopen(req).read()
-        except urllib.error.HTTPError as exc:
-            if exc.code == 400:
-                print("Sorry, the Hub couldn't create your user.")
-                print("You can't register duplicate users, which is the most")
-                print("common cause of this error.  All values for username,")
-                print("name, and email must be unique in our system.")
-                sys.exit(1)
-        except urllib.URLError as exc:
-            print("Something has gone wrong.  Here's the error message.")
-            raise exc
+
+        data = dict(firstName=first_name, email=email, login=username,
+                    password=password1, lastName=last_name, admin=False)
+        hub_url = ytcfg.get("yt", "hub_url")
+        req = requests.post(hub_url + "/user", data=data)
+      
+        if req.ok:
+            headers = {'Girder-Token': req.json()['authToken']['token']}
+        else:
+            if req.status_code == 400:
+                print("Registration failed with 'Bad request':")
+                print(req.json()["message"])
+            exit(1)
+        print("User registration successful")
+        print("Obtaining API key...")
+        req = requests.post(hub_url + "/api_key", headers=headers,
+                            data={'name': 'ytcmd', 'active': True})
+        apiKey = req.json()["key"]
+
+        print("Storing API key in configuration file")
+        set_config("yt", "hub_api_key", apiKey)
+        
         print()
         print("SUCCESS!")
         print()
@@ -814,7 +818,7 @@
     args = (dict(short="file", type=str),)
     description = \
         """
-        Upload an IPython notebook to hub.yt-project.org.
+        Upload an IPython notebook to hub.yt.
         """
 
     name = "upload_notebook"


https://bitbucket.org/yt_analysis/yt/commits/4c5033cb6ec8/
Changeset:   4c5033cb6ec8
Branch:      yt
User:        xarthisius
Date:        2016-07-19 15:06:39+00:00
Summary:     update upload_notebook
Affected #:  1 file

diff -r 33e98387a02196c47cd679082abe8209af03311c -r 4c5033cb6ec8a6e577714f9549d05ab9b6e9ce51 yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -39,6 +39,7 @@
     enable_plugins
 from yt.extern.six import add_metaclass, string_types
 from yt.extern.six.moves import urllib, input
+from yt.extern.six.moves.urllib.parse import urlparse
 from yt.convenience import load
 from yt.visualization.plot_window import \
     SlicePlot, \
@@ -823,31 +824,39 @@
 
     name = "upload_notebook"
     def __call__(self, args):
+        try:
+            import girder_client
+        except ImportError:
+            print("yt {} requires girder_client to be installed".format(self.name))
+            print("Please install them using you python package manager, e.g.:")
+            print("   pip install girder_client --user")
+            exit()
+
         filename = args.file
         if not os.path.isfile(filename):
             raise IOError(filename)
         if not filename.endswith(".ipynb"):
             print("File must be an IPython notebook!")
             return 1
-        import json
-        try:
-            t = json.loads(open(filename).read())['metadata']['name']
-        except (ValueError, KeyError):
-            print("File does not appear to be an IPython notebook.")
-        if len(t) == 0:
-            t = filename.strip(".ipynb")
-        from yt.utilities.minimal_representation import MinimalNotebook
-        mn = MinimalNotebook(filename, t)
-        rv = mn.upload()
+        hub_url = urlparse(ytcfg.get("yt", "hub_url"))
+        gc = girder_client.GirderClient(apiUrl=hub_url.geturl())
+        gc.authenticate(apiKey=ytcfg.get("yt", "hub_api_key"))
+        username = gc.get("/user/me")["login"]
+        gc.upload(filename, "/user/{}/Public".format(username))
+
+        _id = gc.resourceLookup(
+            "/user/{}/Public/{}".format(username, filename))["_id"]
+        _fid = next(gc.listFile(_id))["_id"]
         print("Upload successful!")
         print()
         print("To access your raw notebook go here:")
         print()
-        print("  %s" % (rv['url']))
+        print("  {}://{}/#item/{}".format(hub_url.scheme, hub_url.netloc, _id))
         print()
         print("To view your notebook go here:")
         print()
-        print("  %s" % (rv['url'].replace("/go/", "/nb/")))
+        print("  http://nbviewer.jupyter.org/urls/{}/file/{}/download".format(
+            hub_url.netloc + hub_url.path, _fid))
         print()
 
 class YTPlotCmd(YTCommand):


https://bitbucket.org/yt_analysis/yt/commits/88aed7e7add2/
Changeset:   88aed7e7add2
Branch:      yt
User:        xarthisius
Date:        2016-07-19 15:07:31+00:00
Summary:     Set new default for hub_url
Affected #:  1 file

diff -r 4c5033cb6ec8a6e577714f9549d05ab9b6e9ce51 -r 88aed7e7add222699f5d36fa484e93a128501e06 yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -49,7 +49,7 @@
     test_storage_dir = '/does/not/exist',
     test_data_dir = '/does/not/exist',
     enzo_db = '',
-    hub_url = 'https://hub.yt-project.org/upload',
+    hub_url = 'https://girder.hub.yt/api/v1',
     hub_api_key = '',
     notebook_password = '',
     answer_testing_tolerance = '3',


https://bitbucket.org/yt_analysis/yt/commits/ddd3b93c8cdb/
Changeset:   ddd3b93c8cdb
Branch:      yt
User:        xarthisius
Date:        2016-07-19 15:10:23+00:00
Summary:     Add hub support via 'extras_require'
Affected #:  1 file

diff -r 88aed7e7add222699f5d36fa484e93a128501e06 -r ddd3b93c8cdbbcef8137230b24e842c9a35041d2 setup.py
--- a/setup.py
+++ b/setup.py
@@ -389,6 +389,9 @@
         'IPython',
         'cython',
     ],
+    extras_require = {
+        'hub':  ["girder_client"]
+    },
     cmdclass={'sdist': sdist, 'build_ext': build_ext, 'build_py': build_py},
     author="The yt project",
     author_email="yt-dev at lists.spacepope.org",


https://bitbucket.org/yt_analysis/yt/commits/3b0333996d0b/
Changeset:   3b0333996d0b
Branch:      yt
User:        xarthisius
Date:        2016-07-19 16:06:33+00:00
Summary:     Re add documentation about sharing data
Affected #:  2 files

diff -r ddd3b93c8cdbbcef8137230b24e842c9a35041d2 -r 3b0333996d0baa564399aed5b1ad37818022040d doc/source/reference/index.rst
--- a/doc/source/reference/index.rst
+++ b/doc/source/reference/index.rst
@@ -12,6 +12,7 @@
 
    code_support
    command-line
+   sharing_data
    api/api
    configuration
    python_introduction

diff -r ddd3b93c8cdbbcef8137230b24e842c9a35041d2 -r 3b0333996d0baa564399aed5b1ad37818022040d doc/source/reference/sharing_data.rst
--- /dev/null
+++ b/doc/source/reference/sharing_data.rst
@@ -0,0 +1,83 @@
+
+.. _sharing-data:
+
+What is the yt Hub?
+===================
+
+The yt data Hub is a mechanism by which images, data objects and projects can be
+shared with other people. For instance, one can upload a dataset and allow other
+people to remotely analyze it with a jupyter notebook or upload notebooks and
+view them from any web browser.
+
+.. note:: All items posted on the hub are public!
+
+Over time, more widgets will be added, and more datatypes will be able to be
+uploaded.  If you are interested in adding more ways of sharing data, please
+email the developers' list.  We would like to add support for 3D widgets such
+as isocontours as well as interactive binning and rebinning of data from yt
+data objects, to be displayed as phase plots and profiles.
+
+.. note:: Working with the Hub requires additional dependencies to be installed.
+          You can obtain them by running: ``pip install yt[hub]``. 
+
+Obtaining API key
+-----------------
+
+In order to interact with the yt Hub, you need to obtain API key, which is
+available only for authenticated users. You can `log into
+<https://girder.hub.yt/#?dialog=login>`_ the Hub using your Google, GitHub or
+Bitbucket account. After you log in, API key can be generated in your account
+settings view, which can be accessed through dropdown menu in the upper right
+corner. After you have gotten your API key, update your config file:
+
+.. code-block:: none
+
+   $ yt-config set yt hub_api_key 3fd8de56c2884c13a2de4dd51a80974b
+
+Replace ``3fd8de56c2884c13a2de4dd51a80974b`` with your API key.
+
+Registering a User
+^^^^^^^^^^^^^^^^^^
+
+If you do not wish to use OAuth authentication, you can create a Hub account
+using ``yt`` command. To register a user:
+
+.. code-block:: bash
+
+   $ yt hub_register
+
+This will walk you through the process of registering. You will need to supply
+a name, a username, a password and an email address. Apart from creating a new
+user account, it will also generate an API key and append it to the yt's config
+file.  At this point, you're ready to go!
+
+What Can Be Uploaded
+--------------------
+
+Currently, the yt hub can accept these types of data:
+
+ * Raw data files, scripts.
+ * IPython notebooks: these are stored on the hub and are made available for
+   download and via the IPython `nbviewer <http://nbviewer.ipython.org/>`_
+   service.
+
+How to Upload Data
+------------------
+
+Uploading data can be performed using the ``girder-cli`` command tool or
+directly via the web interface. Please refer to ``girder-cli`` `documentation page
+<http://girder.readthedocs.io/en/latest/python-client.html>`_ for additional
+information.
+
+Uploading Notebooks
+~~~~~~~~~~~~~~~~~~~
+
+Notebooks can be uploaded from the bash command line:
+
+.. code-block:: bash
+
+   yt upload_notebook notebook_file.ipynb
+
+After the notebook is finished uploading, yt will print a link to the raw
+notebook as well as an nbviewer link to the same notebook.  Your notebooks will
+be stored under your hub Public directory.


https://bitbucket.org/yt_analysis/yt/commits/6a3dddd3524c/
Changeset:   6a3dddd3524c
Branch:      yt
User:        xarthisius
Date:        2016-07-25 03:57:14+00:00
Summary:     Backup old config file instead of removing it
Affected #:  1 file

diff -r 3b0333996d0baa564399aed5b1ad37818022040d -r 6a3dddd3524c85e36dcd7616c2decf4d87826ed6 yt/utilities/configure.py
--- a/yt/utilities/configure.py
+++ b/yt/utilities/configure.py
@@ -40,10 +40,10 @@
         print("Old config not found.")
         sys.exit()
     CONFIG.read(__OLD_CONFIG_FILE)
-    print("Writing new config file to: {}".format(CURRENT_CONFIG_FILE))
+    print("Writing a new config file to: {}".format(CURRENT_CONFIG_FILE))
     write_config()
-    print("Removing old config file: {}".format(__OLD_CONFIG_FILE))
-    os.remove(__OLD_CONFIG_FILE)
+    print("Backing up the old config file: {}".format(__OLD_CONFIG_FILE))
+    os.rename(__OLD_CONFIG_FILE, __OLD_CONFIG_FILE + '.bak')
 
 
 def rm_config(section, option):


https://bitbucket.org/yt_analysis/yt/commits/c2cdee3135c3/
Changeset:   c2cdee3135c3
Branch:      yt
User:        xarthisius
Date:        2016-07-26 16:55:06+00:00
Summary:     Update cmd-line docs
Affected #:  2 files

diff -r 6a3dddd3524c85e36dcd7616c2decf4d87826ed6 -r c2cdee3135c306933ac6ab1fdd4d88a609417dda doc/source/reference/command-line.rst
--- a/doc/source/reference/command-line.rst
+++ b/doc/source/reference/command-line.rst
@@ -57,12 +57,8 @@
 .. code-block:: bash
 
     help                Print help message
-    bootstrap_dev       Bootstrap a yt development environment
     bugreport           Report a bug in yt
-    hub_register        Register a user on the Hub: http://hub.yt-project.org/
-    hub_submit          Submit a mercurial repository to the yt Hub
-                        (http://hub.yt-project.org/), creating a BitBucket
-                        repo in the process if necessary.
+    hub_register        Register a user on the Hub: https://hub.yt/
     instinfo            Get some information about the yt installation
     version             Get some information about the yt installation (this
                         is an alias for instinfo).
@@ -70,7 +66,7 @@
     mapserver           Serve a plot in a GMaps-style interface
     pastebin            Post a script to an anonymous pastebin
     pastebin_grab       Print an online pastebin to STDOUT for local use.
-    upload_notebook     Upload an IPython notebook to hub.yt-project.org.
+    upload_notebook     Upload an IPython notebook to the yt Hub.
     plot                Create a set of images
     rpdb                Connect to a currently running (on localhost) rpd
                         session. Commands run with --rpdb will trigger an rpdb
@@ -272,3 +268,68 @@
 The image uploaded using ``upload_image`` is assigned with a unique hash that
 can be used to remove it. This subcommand provides an easy way to send a delete
 request directly to the `imgur.com <http://imgur.com/>`_.
+
+Config helper
+~~~~~~~~~~~~~
+
+The :code:`yt-config` command-line tool allows you to modify and access the yt's
+configuration without manually locating and opening the config file in an editor.
+To get a quick list of available commands, just type:
+
+.. code-block:: bash
+
+   yt-config -h
+
+This will print the list of available subcommands:
+
+.. code-block:: bash
+
+	get                 get a config value
+	set                 set a config value
+	rm                  remove a config option
+	migrate             migrate old config file
+	list                show all config values
+
+Since the yt version 3.3.2, the previous location of the configuration file
+(``$HOME/.yt/config``) has been deprecated in favor of a location adhering to the
+`XDG Base Directory Specification
+<https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html>`_.
+(``$XDG_HOME_CONFIG/yt/ytrc``). In order to perform an automatic migration of
+the old config, you are encouraged to run:
+
+.. code-block:: bash
+
+   yt-config migrate
+
+that will copy your current config file to the new location and store a backup
+copy as ``$HOME/.yt/config.bak``.
+
+Examples
+++++++++
+
+Listing current content of the config file:
+
+.. code-block:: bash
+
+   $ yt-config list
+   [yt]
+   loglevel = 50
+
+Obtaining a single config value by name:
+
+.. code-block:: bash
+
+   $ yt-config get yt loglevel
+   50
+
+Changing a single config value:
+
+.. code-block:: bash
+
+   $ yt-config set yt loglevel 10
+
+Removing a single config entry:
+
+.. code-block:: bash
+
+   $ yt-config rm yt loglevel

diff -r 6a3dddd3524c85e36dcd7616c2decf4d87826ed6 -r c2cdee3135c306933ac6ab1fdd4d88a609417dda yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -819,7 +819,7 @@
     args = (dict(short="file", type=str),)
     description = \
         """
-        Upload an IPython notebook to hub.yt.
+        Upload an IPython notebook to the yt Hub.
         """
 
     name = "upload_notebook"


https://bitbucket.org/yt_analysis/yt/commits/88191c24c9c9/
Changeset:   88191c24c9c9
Branch:      yt
User:        xarthisius
Date:        2016-07-26 18:09:09+00:00
Summary:     Add basic tests
Affected #:  3 files

diff -r c2cdee3135c306933ac6ab1fdd4d88a609417dda -r 88191c24c9c9b01eab9718b286df974aece002b3 yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -75,21 +75,21 @@
     os.makedirs(CONFIG_DIR)
 
 CURRENT_CONFIG_FILE = os.path.join(CONFIG_DIR, 'ytrc')
-__OLD_CONFIG_FILE = os.path.join(os.path.expanduser('~'), '.yt', 'config')
+_OLD_CONFIG_FILE = os.path.join(os.path.expanduser('~'), '.yt', 'config')
 
 # Here is the upgrade.  We're actually going to parse the file in its entirety
 # here.  Then, if it has any of the Forbidden Sections, it will be rewritten
 # without them.
 
-if os.path.exists(__OLD_CONFIG_FILE):
-    f = open(__OLD_CONFIG_FILE).read()
+if os.path.exists(_OLD_CONFIG_FILE):
+    f = open(_OLD_CONFIG_FILE).read()
     if any(header in f for header in ["[lagos]","[raven]","[fido]","[enki]"]):
         print("***********************************************************")
         print("* Upgrading configuration file to new format; saving old. *")
         print("***********************************************************")
         # This is of the old format
         cp = configparser.ConfigParser()
-        cp.read(__OLD_CONFIG_FILE)
+        cp.read(_OLD_CONFIG_FILE)
         # NOTE: To avoid having the 'DEFAULT' section here,
         # we are not passing in ytcfg_defaults to the constructor.
         new_cp = configparser.ConfigParser()
@@ -100,15 +100,15 @@
                 if option.lower() in ytcfg_defaults:
                     new_cp.set("yt", option, cp.get(section, option))
                     print("Setting %s to %s" % (option, cp.get(section, option)))
-        open(__OLD_CONFIG_FILE + ".old", "w").write(f)
-        new_cp.write(open(__OLD_CONFIG_FILE, "w"))
+        open(_OLD_CONFIG_FILE + ".old", "w").write(f)
+        new_cp.write(open(_OLD_CONFIG_FILE, "w"))
 
     msg = (
         "The configuration file {} is deprecated. "
         "Please migrate your config to {} by running: "
         "'yt-config migrate'"
     )
-    warnings.warn(msg.format(__OLD_CONFIG_FILE, CURRENT_CONFIG_FILE))
+    warnings.warn(msg.format(_OLD_CONFIG_FILE, CURRENT_CONFIG_FILE))
 
 if not os.path.exists(CURRENT_CONFIG_FILE):
     cp = configparser.ConfigParser()
@@ -123,7 +123,7 @@
         self.get(key[0], key[1])
 
 ytcfg = YTConfigParser(ytcfg_defaults)
-ytcfg.read([__OLD_CONFIG_FILE, CURRENT_CONFIG_FILE, 'yt.cfg'])
+ytcfg.read([_OLD_CONFIG_FILE, CURRENT_CONFIG_FILE, 'yt.cfg'])
 if not ytcfg.has_section("yt"):
     ytcfg.add_section("yt")
 

diff -r c2cdee3135c306933ac6ab1fdd4d88a609417dda -r 88191c24c9c9b01eab9718b286df974aece002b3 yt/utilities/configure.py
--- a/yt/utilities/configure.py
+++ b/yt/utilities/configure.py
@@ -10,7 +10,7 @@
 import os
 import sys
 import argparse
-from yt.config import CURRENT_CONFIG_FILE, __OLD_CONFIG_FILE
+from yt.config import CURRENT_CONFIG_FILE, _OLD_CONFIG_FILE
 from yt.extern.six.moves import configparser
 
 CONFIG = configparser.SafeConfigParser()
@@ -36,14 +36,14 @@
         CONFIG.write(fd)
 
 def migrate_config():
-    if not os.path.exists(__OLD_CONFIG_FILE):
+    if not os.path.exists(_OLD_CONFIG_FILE):
         print("Old config not found.")
         sys.exit()
-    CONFIG.read(__OLD_CONFIG_FILE)
+    CONFIG.read(_OLD_CONFIG_FILE)
     print("Writing a new config file to: {}".format(CURRENT_CONFIG_FILE))
     write_config()
-    print("Backing up the old config file: {}".format(__OLD_CONFIG_FILE))
-    os.rename(__OLD_CONFIG_FILE, __OLD_CONFIG_FILE + '.bak')
+    print("Backing up the old config file: {}".format(_OLD_CONFIG_FILE))
+    os.rename(_OLD_CONFIG_FILE, _OLD_CONFIG_FILE + '.bak')
 
 
 def rm_config(section, option):

diff -r c2cdee3135c306933ac6ab1fdd4d88a609417dda -r 88191c24c9c9b01eab9718b286df974aece002b3 yt/utilities/tests/test_config.py
--- /dev/null
+++ b/yt/utilities/tests/test_config.py
@@ -0,0 +1,133 @@
+import contextlib
+import mock
+import os
+import sys
+import unittest
+import yt.utilities.configure
+import yt.config
+from yt.config import \
+    CURRENT_CONFIG_FILE, _OLD_CONFIG_FILE
+from yt.extern.six import StringIO
+from yt.extern.six.moves.configparser import NoOptionError, SafeConfigParser
+
+
+_DUMMY_CFG = ['[yt]', 'loglevel = 49']
+
+
+ at contextlib.contextmanager
+def captureOutput():
+    oldout, olderr = sys.stdout, sys.stderr
+    try:
+        out = [StringIO(), StringIO()]
+        sys.stdout, sys.stderr = out
+        yield out
+    finally:
+        sys.stdout, sys.stderr = oldout, olderr
+        out[0] = out[0].getvalue()
+        out[1] = out[1].getvalue()
+
+
+class SysExitException(Exception):
+    pass
+
+
+def setUpModule():
+    for cfgfile in (CURRENT_CONFIG_FILE, _OLD_CONFIG_FILE):
+        if os.path.exists(cfgfile):
+            os.rename(cfgfile, cfgfile + '.bak_test')
+
+            if cfgfile == CURRENT_CONFIG_FILE:
+                yt.utilities.configure.CONFIG = SafeConfigParser()
+                if not yt.utilities.configure.CONFIG.has_section('yt'):
+                    yt.utilities.configure.CONFIG.add_section('yt')
+
+
+def tearDownModule():
+    for cfgfile in (CURRENT_CONFIG_FILE, _OLD_CONFIG_FILE): 
+        if os.path.exists(cfgfile + '.bak_test'):
+            os.rename(cfgfile + '.bak_test', cfgfile)
+
+
+class TestYTConfig(unittest.TestCase):
+    def _runYTConfig(self, args):
+        args = ['yt-config'] + args
+        retcode = 0
+
+        with mock.patch.object(sys, 'argv', args),\
+                mock.patch('sys.exit', side_effect=SysExitException) as exit,\
+                captureOutput() as output:
+            try:
+                yt.utilities.configure.main()
+            except SysExitException:
+                args = exit.mock_calls[0][1]
+                retcode = args[0] if len(args) else 0
+        return {
+            'rc': retcode,
+            'stdout': output[0],
+            'stderr': output[1]
+        }
+
+class TestYTConfigCommands(TestYTConfig):
+    def testConfigCommands(self):
+        self.assertFalse(os.path.exists(CURRENT_CONFIG_FILE))
+
+        info = self._runYTConfig(['--help'])
+        self.assertEqual(info['rc'], 0)
+        self.assertEqual(info['stderr'], '')
+        self.assertIn('Get and set configuration values for yt',
+                      info['stdout'])
+
+        info = self._runYTConfig(['list'])
+        self.assertEqual(info['rc'], 0)
+        self.assertIn('[yt]', info['stdout'])
+
+        info = self._runYTConfig(['set', 'yt', '__parallel', 'True'])
+        self.assertEqual(info['rc'], 0)
+
+        info = self._runYTConfig(['get', 'yt', '__parallel'])
+        self.assertEqual(info['rc'], 0)
+        self.assertEqual(info['stdout'].strip(), 'True')
+
+        info = self._runYTConfig(['rm', 'yt', '__parallel'])
+        self.assertEqual(info['rc'], 0)
+
+        with self.assertRaises(NoOptionError):
+            self._runYTConfig(['get', 'yt', 'foo'])
+    
+    def tearDown(self):
+        if os.path.exists(CURRENT_CONFIG_FILE):
+            os.remove(CURRENT_CONFIG_FILE)
+
+class TestYTConfigMigration(TestYTConfig):
+
+    def setUp(self):
+        if not os.path.exists(os.path.dirname(_OLD_CONFIG_FILE)):
+            os.makedirs(os.path.dirname(_OLD_CONFIG_FILE))
+
+        with open(_OLD_CONFIG_FILE, 'w') as fh:
+            for line in _DUMMY_CFG:
+                fh.write('{}\n'.format(line))
+        
+        if os.path.exists(CURRENT_CONFIG_FILE):
+            os.remove(CURRENT_CONFIG_FILE)
+
+    def tearDown(self):
+        if os.path.exists(CURRENT_CONFIG_FILE):
+            os.remove(CURRENT_CONFIG_FILE)
+        if os.path.exists(_OLD_CONFIG_FILE + '.bak'):
+            os.remove(_OLD_CONFIG_FILE + '.bak')
+
+    def testConfigMigration(self):
+        self.assertFalse(os.path.exists(CURRENT_CONFIG_FILE))
+        self.assertTrue(os.path.exists(_OLD_CONFIG_FILE))
+        
+        info = self._runYTConfig(['migrate'])
+        self.assertEqual(info['rc'], 0)
+
+        self.assertTrue(os.path.exists(CURRENT_CONFIG_FILE))
+        self.assertFalse(os.path.exists(_OLD_CONFIG_FILE))
+        self.assertTrue(os.path.exists(_OLD_CONFIG_FILE + '.bak'))
+
+        with open(CURRENT_CONFIG_FILE, 'r') as fh:
+            new_cfg = ''.join(fh.readlines())
+        self.assertEqual(new_cfg.strip().split('\n'), _DUMMY_CFG)


https://bitbucket.org/yt_analysis/yt/commits/c6c6be0cdb3d/
Changeset:   c6c6be0cdb3d
Branch:      yt
User:        xarthisius
Date:        2016-07-26 18:11:54+00:00
Summary:     Add preamble
Affected #:  1 file

diff -r 88191c24c9c9b01eab9718b286df974aece002b3 -r c6c6be0cdb3d552aa3a15c7a47d4434f3136183b yt/utilities/tests/test_config.py
--- a/yt/utilities/tests/test_config.py
+++ b/yt/utilities/tests/test_config.py
@@ -1,3 +1,12 @@
+# -*- coding: UTF-8 -*-
+#-----------------------------------------------------------------------------
+# Copyright (c) 2016, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
 import contextlib
 import mock
 import os


https://bitbucket.org/yt_analysis/yt/commits/3c4ffb7054b0/
Changeset:   3c4ffb7054b0
Branch:      yt
User:        xarthisius
Date:        2016-08-01 22:17:01+00:00
Summary:     Add hubstart command. Obsoletes PR 1444
Affected #:  3 files

diff -r c6c6be0cdb3d552aa3a15c7a47d4434f3136183b -r 3c4ffb7054b085c6572f46087b0225e70fdb1d09 doc/source/reference/command-line.rst
--- a/doc/source/reference/command-line.rst
+++ b/doc/source/reference/command-line.rst
@@ -58,7 +58,7 @@
 
     help                Print help message
     bugreport           Report a bug in yt
-    hub_register        Register a user on the Hub: https://hub.yt/
+    hub_register        Register a user on the yt Hub: https://hub.yt/
     instinfo            Get some information about the yt installation
     version             Get some information about the yt installation (this
                         is an alias for instinfo).
@@ -66,18 +66,21 @@
     mapserver           Serve a plot in a GMaps-style interface
     pastebin            Post a script to an anonymous pastebin
     pastebin_grab       Print an online pastebin to STDOUT for local use.
-    upload_notebook     Upload an IPython notebook to the yt Hub.
+    hubstart            Start the Jupyter Notebook on the yt Hub. 
+    upload_notebook     Upload an IPython Notebook to the yt Hub.
     plot                Create a set of images
     rpdb                Connect to a currently running (on localhost) rpd
                         session. Commands run with --rpdb will trigger an rpdb
                         session with any uncaught exceptions.
-    notebook            Run the IPython Notebook
+    notebook            Start the Jupyter Notebook locally.
     stats               Print stats and max/min value of a given field (if
                         requested), for one or more datasets (default field is
                         Density)
     update              Update the yt installation to the most recent version
     delete_image        Delete image from imgur.com.
     upload_image        Upload an image to imgur.com. Must be PNG.
+    search              Attempt to find outputs that yt can recognize in
+                        directories.
 
 
 To execute any such function, simply run:

diff -r c6c6be0cdb3d552aa3a15c7a47d4434f3136183b -r 3c4ffb7054b085c6572f46087b0225e70fdb1d09 yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -51,6 +51,7 @@
     enzo_db = '',
     hub_url = 'https://girder.hub.yt/api/v1',
     hub_api_key = '',
+    hub_sandbox = '/collection/yt_sandbox/data',
     notebook_password = '',
     answer_testing_tolerance = '3',
     answer_testing_bitwise = 'False',

diff -r c6c6be0cdb3d552aa3a15c7a47d4434f3136183b -r 3c4ffb7054b085c6572f46087b0225e70fdb1d09 yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -119,6 +119,22 @@
         print("Changeset = %s" % vstring.strip().decode("utf-8"))
     print("---")
     return vstring
+    
+
+def _get_girder_client():
+    try:
+        import girder_client
+    except ImportError:
+        print("this command requires girder_client to be installed")
+        print("Please install them using you python package manager, e.g.:")
+        print("   pip install girder_client --user")
+        exit()
+
+    hub_url = urlparse(ytcfg.get("yt", "hub_url"))
+    gc = girder_client.GirderClient(apiUrl=hub_url.geturl())
+    gc.authenticate(apiKey=ytcfg.get("yt", "hub_api_key"))
+    return gc
+
 
 class YTCommandSubtype(type):
     def __init__(cls, name, b, d):
@@ -562,7 +578,7 @@
     name = "hub_register"
     description = \
         """
-        Register a user on the Hub: http://hub.yt/
+        Register a user on the yt Hub: http://hub.yt/
         """
     def __call__(self, args):
         try:
@@ -815,38 +831,45 @@
         import yt.utilities.lodgeit as lo
         lo.main( None, download=args.number )
 
+class YTHubStartNotebook(YTCommand):
+    args = ()
+    description = \
+        """
+        Start the Jupyter Notebook on the yt Hub.
+        """
+    name = "hubstart"
+    def __call__(self, args):
+        gc = _get_girder_client()
+
+        # TODO: should happen server-side
+        _id = gc._checkResourcePath(ytcfg.get("yt", "hub_sandbox"))
+
+        resp = gc.post("/notebook/{}".format(_id))
+        try:
+            print("Launched! Please visit this URL:")
+            print("    https://tmpnb.hub.yt" + resp['url'])
+            print()
+        except KeyError:
+            print("Something went wrong. The yt Hub responded with : ")
+            print(resp)
+
 class YTNotebookUploadCmd(YTCommand):
     args = (dict(short="file", type=str),)
     description = \
         """
-        Upload an IPython notebook to the yt Hub.
+        Upload an IPython Notebook to the yt Hub.
         """
 
     name = "upload_notebook"
     def __call__(self, args):
-        try:
-            import girder_client
-        except ImportError:
-            print("yt {} requires girder_client to be installed".format(self.name))
-            print("Please install them using you python package manager, e.g.:")
-            print("   pip install girder_client --user")
-            exit()
-
-        filename = args.file
-        if not os.path.isfile(filename):
-            raise IOError(filename)
-        if not filename.endswith(".ipynb"):
-            print("File must be an IPython notebook!")
-            return 1
-        hub_url = urlparse(ytcfg.get("yt", "hub_url"))
-        gc = girder_client.GirderClient(apiUrl=hub_url.geturl())
-        gc.authenticate(apiKey=ytcfg.get("yt", "hub_api_key"))
+        gc = _get_girder_client()
         username = gc.get("/user/me")["login"]
-        gc.upload(filename, "/user/{}/Public".format(username))
+        gc.upload(args.file, "/user/{}/Public".format(username))
 
         _id = gc.resourceLookup(
-            "/user/{}/Public/{}".format(username, filename))["_id"]
+            "/user/{}/Public/{}".format(username, args.file))["_id"]
         _fid = next(gc.listFile(_id))["_id"]
+        hub_url = urlparse(ytcfg.get("yt", "hub_url"))
         print("Upload successful!")
         print()
         print("To access your raw notebook go here:")
@@ -960,7 +983,7 @@
             )
     description = \
         """
-        Run the IPython Notebook
+        Start the Jupyter Notebook locally. 
         """
     def __call__(self, args):
         kwargs = {}


https://bitbucket.org/yt_analysis/yt/commits/3fac47f991c9/
Changeset:   3fac47f991c9
Branch:      yt
User:        xarthisius
Date:        2016-08-01 22:32:42+00:00
Summary:     Add docs for hub_register and hubstart
Affected #:  1 file

diff -r 3c4ffb7054b085c6572f46087b0225e70fdb1d09 -r 3fac47f991c91d15a0f856e2926a806ecaf9dbe8 doc/source/reference/command-line.rst
--- a/doc/source/reference/command-line.rst
+++ b/doc/source/reference/command-line.rst
@@ -216,13 +216,29 @@
 
 This command will accept the filename of a ``.ipynb`` file (generated from an
 IPython notebook session) and upload it to the `yt hub
-<http://hub.yt-project.org/>` where others will be able to view it, and
+<https://hub.yt/>`_ where others will be able to view it, and
 download it.  This is an easy method for recording a sequence of commands,
 their output, narrative information, and then sharing that with others.  These
 notebooks will be viewable online, and the appropriate URLs will be returned on
 the command line.
 
 
+hub_register
+++++++++++++
+
+This commands starts an interactive process of creating an account on the `yt
+hub <https://hub.yt/>`_. Please note that the yt Hub also supports multiple OAuth
+providers such as Google, Bitbucket and GitHub for authentication. 
+See :ref:`sharing-data` for more information.
+
+hubstart
+++++++++
+
+This command launches the Jupyter Notebook on the `yt hub <https://hub.yt>`_
+with a direct access to all the `example yt datasets
+<https://yt-project.org/data>`_. The appropriate URL allowing to access the
+Notebook will be return on the commandline.
+
 rpdb
 ++++
 


https://bitbucket.org/yt_analysis/yt/commits/c600c4e20077/
Changeset:   c600c4e20077
Branch:      yt
User:        xarthisius
Date:        2016-08-01 22:53:44+00:00
Summary:     Adjust section structure per Nathan's comment
Affected #:  2 files

diff -r 3fac47f991c91d15a0f856e2926a806ecaf9dbe8 -r c600c4e200772c229b8f48170bea7ca28c3e4649 doc/source/reference/index.rst
--- a/doc/source/reference/index.rst
+++ b/doc/source/reference/index.rst
@@ -12,7 +12,6 @@
 
    code_support
    command-line
-   sharing_data
    api/api
    configuration
    python_introduction

diff -r 3fac47f991c91d15a0f856e2926a806ecaf9dbe8 -r c600c4e200772c229b8f48170bea7ca28c3e4649 doc/source/reference/sharing_data.rst
--- a/doc/source/reference/sharing_data.rst
+++ b/doc/source/reference/sharing_data.rst
@@ -1,8 +1,11 @@
 
 .. _sharing-data:
 
+The yt Hub
+==========
+
 What is the yt Hub?
-===================
+-------------------
 
 The yt data Hub is a mechanism by which images, data objects and projects can be
 shared with other people. For instance, one can upload a dataset and allow other


https://bitbucket.org/yt_analysis/yt/commits/dc0ca19312ed/
Changeset:   dc0ca19312ed
Branch:      yt
User:        xarthisius
Date:        2016-08-01 22:54:41+00:00
Summary:     Move sharing_data up in the index tree
Affected #:  3 files

diff -r c600c4e200772c229b8f48170bea7ca28c3e4649 -r dc0ca19312ed4e6cb776887cb7ad626ab458869c doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -185,6 +185,7 @@
    analyzing/analysis_modules/index
    examining/index
    developing/index
+   sharing_data
    reference/index
    faq/index
    Getting Help <help/index>

diff -r c600c4e200772c229b8f48170bea7ca28c3e4649 -r dc0ca19312ed4e6cb776887cb7ad626ab458869c doc/source/reference/sharing_data.rst
--- a/doc/source/reference/sharing_data.rst
+++ /dev/null
@@ -1,86 +0,0 @@
-
-.. _sharing-data:
-
-The yt Hub
-==========
-
-What is the yt Hub?
--------------------
-
-The yt data Hub is a mechanism by which images, data objects and projects can be
-shared with other people. For instance, one can upload a dataset and allow other
-people to remotely analyze it with a jupyter notebook or upload notebooks and
-view them from any web browser.
-
-.. note:: All items posted on the hub are public!
-
-Over time, more widgets will be added, and more datatypes will be able to be
-uploaded.  If you are interested in adding more ways of sharing data, please
-email the developers' list.  We would like to add support for 3D widgets such
-as isocontours as well as interactive binning and rebinning of data from yt
-data objects, to be displayed as phase plots and profiles.
-
-.. note:: Working with the Hub requires additional dependencies to be installed.
-          You can obtain them by running: ``pip install yt[hub]``. 
-
-Obtaining API key
------------------
-
-In order to interact with the yt Hub, you need to obtain API key, which is
-available only for authenticated users. You can `log into
-<https://girder.hub.yt/#?dialog=login>`_ the Hub using your Google, GitHub or
-Bitbucket account. After you log in, API key can be generated in your account
-settings view, which can be accessed through dropdown menu in the upper right
-corner. After you have gotten your API key, update your config file:
-
-.. code-block:: none
-
-   $ yt-config set yt hub_api_key 3fd8de56c2884c13a2de4dd51a80974b
-
-Replace ``3fd8de56c2884c13a2de4dd51a80974b`` with your API key.
-
-Registering a User
-^^^^^^^^^^^^^^^^^^
-
-If you do not wish to use OAuth authentication, you can create a Hub account
-using ``yt`` command. To register a user:
-
-.. code-block:: bash
-
-   $ yt hub_register
-
-This will walk you through the process of registering. You will need to supply
-a name, a username, a password and an email address. Apart from creating a new
-user account, it will also generate an API key and append it to the yt's config
-file.  At this point, you're ready to go!
-
-What Can Be Uploaded
---------------------
-
-Currently, the yt hub can accept these types of data:
-
- * Raw data files, scripts.
- * IPython notebooks: these are stored on the hub and are made available for
-   download and via the IPython `nbviewer <http://nbviewer.ipython.org/>`_
-   service.
-
-How to Upload Data
-------------------
-
-Uploading data can be performed using the ``girder-cli`` command tool or
-directly via the web interface. Please refer to ``girder-cli`` `documentation page
-<http://girder.readthedocs.io/en/latest/python-client.html>`_ for additional
-information.
-
-Uploading Notebooks
-~~~~~~~~~~~~~~~~~~~
-
-Notebooks can be uploaded from the bash command line:
-
-.. code-block:: bash
-
-   yt upload_notebook notebook_file.ipynb
-
-After the notebook is finished uploading, yt will print a link to the raw
-notebook as well as an nbviewer link to the same notebook.  Your notebooks will
-be stored under your hub Public directory.

diff -r c600c4e200772c229b8f48170bea7ca28c3e4649 -r dc0ca19312ed4e6cb776887cb7ad626ab458869c doc/source/sharing_data.rst
--- /dev/null
+++ b/doc/source/sharing_data.rst
@@ -0,0 +1,86 @@
+
+.. _sharing-data:
+
+The yt Hub
+==========
+
+What is the yt Hub?
+-------------------
+
+The yt data Hub is a mechanism by which images, data objects and projects can be
+shared with other people. For instance, one can upload a dataset and allow other
+people to remotely analyze it with a jupyter notebook or upload notebooks and
+view them from any web browser.
+
+.. note:: All items posted on the hub are public!
+
+Over time, more widgets will be added, and more datatypes will be able to be
+uploaded.  If you are interested in adding more ways of sharing data, please
+email the developers' list.  We would like to add support for 3D widgets such
+as isocontours as well as interactive binning and rebinning of data from yt
+data objects, to be displayed as phase plots and profiles.
+
+.. note:: Working with the Hub requires additional dependencies to be installed.
+          You can obtain them by running: ``pip install yt[hub]``. 
+
+Obtaining API key
+-----------------
+
+In order to interact with the yt Hub, you need to obtain API key, which is
+available only for authenticated users. You can `log into
+<https://girder.hub.yt/#?dialog=login>`_ the Hub using your Google, GitHub or
+Bitbucket account. After you log in, API key can be generated in your account
+settings view, which can be accessed through dropdown menu in the upper right
+corner. After you have gotten your API key, update your config file:
+
+.. code-block:: none
+
+   $ yt-config set yt hub_api_key 3fd8de56c2884c13a2de4dd51a80974b
+
+Replace ``3fd8de56c2884c13a2de4dd51a80974b`` with your API key.
+
+Registering a User
+^^^^^^^^^^^^^^^^^^
+
+If you do not wish to use OAuth authentication, you can create a Hub account
+using ``yt`` command. To register a user:
+
+.. code-block:: bash
+
+   $ yt hub_register
+
+This will walk you through the process of registering. You will need to supply
+a name, a username, a password and an email address. Apart from creating a new
+user account, it will also generate an API key and append it to the yt's config
+file.  At this point, you're ready to go!
+
+What Can Be Uploaded
+--------------------
+
+Currently, the yt hub can accept these types of data:
+
+ * Raw data files, scripts.
+ * IPython notebooks: these are stored on the hub and are made available for
+   download and via the IPython `nbviewer <http://nbviewer.ipython.org/>`_
+   service.
+
+How to Upload Data
+------------------
+
+Uploading data can be performed using the ``girder-cli`` command tool or
+directly via the web interface. Please refer to ``girder-cli`` `documentation page
+<http://girder.readthedocs.io/en/latest/python-client.html>`_ for additional
+information.
+
+Uploading Notebooks
+~~~~~~~~~~~~~~~~~~~
+
+Notebooks can be uploaded from the bash command line:
+
+.. code-block:: bash
+
+   yt upload_notebook notebook_file.ipynb
+
+After the notebook is finished uploading, yt will print a link to the raw
+notebook as well as an nbviewer link to the same notebook.  Your notebooks will
+be stored under your hub Public directory.


https://bitbucket.org/yt_analysis/yt/commits/d1aa47794bbf/
Changeset:   d1aa47794bbf
Branch:      yt
User:        xarthisius
Date:        2016-08-01 22:55:38+00:00
Summary:     Fix typo
Affected #:  1 file

diff -r dc0ca19312ed4e6cb776887cb7ad626ab458869c -r d1aa47794bbf96059de120a8545b994ad82c1873 yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -126,7 +126,7 @@
         import girder_client
     except ImportError:
         print("this command requires girder_client to be installed")
-        print("Please install them using you python package manager, e.g.:")
+        print("Please install them using your python package manager, e.g.:")
         print("   pip install girder_client --user")
         exit()
 
@@ -585,7 +585,7 @@
             import requests
         except ImportError:
             print("yt {} requires requests to be installed".format(self.name))
-            print("Please install them using you python package manager, e.g.:")
+            print("Please install them using your python package manager, e.g.:")
             print("   pip install requests --user")
             exit()
         if ytcfg.get("yt", "hub_api_key") != "":


https://bitbucket.org/yt_analysis/yt/commits/074a1f7af5ee/
Changeset:   074a1f7af5ee
Branch:      yt
User:        xarthisius
Date:        2016-08-02 13:42:38+00:00
Summary:     Fix sphinx warnings
Affected #:  3 files

diff -r d1aa47794bbf96059de120a8545b994ad82c1873 -r 074a1f7af5eeb677899caa775260cd6dff1dc220 doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -133,6 +133,16 @@
      <tr valign="top"><td width="25%"><p>
+           <a href="sharing_data.html">Sharing Data</a>
+         </p>
+       </td>
+       <td width="75%">
+         <p class="linkdescr">The yt Hub</p>
+       </td>
+     </tr>
+     <tr valign="top">
+       <td width="25%">
+         <p><a href="reference/index.html">Reference Materials</a></p></td>

diff -r d1aa47794bbf96059de120a8545b994ad82c1873 -r 074a1f7af5eeb677899caa775260cd6dff1dc220 doc/source/reference/command-line.rst
--- a/doc/source/reference/command-line.rst
+++ b/doc/source/reference/command-line.rst
@@ -216,7 +216,7 @@
 
 This command will accept the filename of a ``.ipynb`` file (generated from an
 IPython notebook session) and upload it to the `yt hub
-<https://hub.yt/>`_ where others will be able to view it, and
+<https://hub.yt/>`__ where others will be able to view it, and
 download it.  This is an easy method for recording a sequence of commands,
 their output, narrative information, and then sharing that with others.  These
 notebooks will be viewable online, and the appropriate URLs will be returned on
@@ -227,14 +227,14 @@
 ++++++++++++
 
 This commands starts an interactive process of creating an account on the `yt
-hub <https://hub.yt/>`_. Please note that the yt Hub also supports multiple OAuth
+hub <https://hub.yt/>`__. Please note that the yt Hub also supports multiple OAuth
 providers such as Google, Bitbucket and GitHub for authentication. 
 See :ref:`sharing-data` for more information.
 
 hubstart
 ++++++++
 
-This command launches the Jupyter Notebook on the `yt hub <https://hub.yt>`_
+This command launches the Jupyter Notebook on the `yt hub <https://hub.yt>`__
 with a direct access to all the `example yt datasets
 <https://yt-project.org/data>`_. The appropriate URL allowing to access the
 Notebook will be return on the commandline.

diff -r d1aa47794bbf96059de120a8545b994ad82c1873 -r 074a1f7af5eeb677899caa775260cd6dff1dc220 doc/source/sharing_data.rst
--- a/doc/source/sharing_data.rst
+++ b/doc/source/sharing_data.rst
@@ -1,9 +1,13 @@
-
 .. _sharing-data:
 
 The yt Hub
 ==========
 
+.. contents::
+   :depth: 2
+   :local:
+   :backlinks: none
+
 What is the yt Hub?
 -------------------
 
@@ -73,7 +77,7 @@
 information.
 
 Uploading Notebooks
-~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^
 
 Notebooks can be uploaded from the bash command line:
 


https://bitbucket.org/yt_analysis/yt/commits/0191e92c97b3/
Changeset:   0191e92c97b3
Branch:      yt
User:        MatthewTurk
Date:        2016-08-02 01:54:05+00:00
Summary:     Experimental sub-sub-parsers for yt command line.
Affected #:  1 file

diff -r 074a1f7af5eeb677899caa775260cd6dff1dc220 -r 0191e92c97b3be82802261843695dceba948dc77 yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -136,15 +136,22 @@
     return gc
 
 
+_subparsers = {None: subparsers}
 class YTCommandSubtype(type):
     def __init__(cls, name, b, d):
         type.__init__(cls, name, b, d)
         if cls.name is not None:
             names = ensure_list(cls.name)
+            if cls.subparser not in _subparsers:
+                parent_parser = argparse.ArgumentParser(add_help=False)    
+                p = subparsers.add_parser(cls.subparser,
+                            help = cls.subparser, parents=[parent_parser])
+                _subparsers[cls.subparser] = p.add_subparsers(title=cls.subparser,
+                        dest=cls.subparser)
+            sp = _subparsers[cls.subparser]
             for name in names:
-                sc = subparsers.add_parser(name,
-                    description = cls.description,
-                    help = cls.description)
+                sc = sp.add_parser(name, description = cls.description, 
+                                   help = cls.description)
                 sc.set_defaults(func=cls.run)
                 for arg in cls.args:
                     _add_arg(sc, arg)
@@ -156,6 +163,7 @@
     description = ""
     aliases = ()
     ndatasets = 1
+    subparser = None
 
     @classmethod
     def run(cls, args):


https://bitbucket.org/yt_analysis/yt/commits/676146ba9b5b/
Changeset:   676146ba9b5b
Branch:      yt
User:        xarthisius
Date:        2016-08-02 14:48:42+00:00
Summary:     Convert yt-config to yt's subparser
Affected #:  3 files

diff -r 0191e92c97b3be82802261843695dceba948dc77 -r 676146ba9b5bebb15f0a252b0acb9710ad77c415 setup.py
--- a/setup.py
+++ b/setup.py
@@ -369,7 +369,6 @@
     'amr adaptivemeshrefinement',
     entry_points={'console_scripts': [
         'yt = yt.utilities.command_line:run_main',
-        'yt-config = yt.utilities.configure:main',
     ],
         'nose.plugins.0.10': [
             'answer-testing = yt.utilities.answer_testing.framework:AnswerTesting'

diff -r 0191e92c97b3be82802261843695dceba948dc77 -r 676146ba9b5bebb15f0a252b0acb9710ad77c415 yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -137,21 +137,29 @@
 
 
 _subparsers = {None: subparsers}
+_subparsers_description = {
+    'config': 'Get and set configuration values for yt'
+}
 class YTCommandSubtype(type):
     def __init__(cls, name, b, d):
         type.__init__(cls, name, b, d)
         if cls.name is not None:
             names = ensure_list(cls.name)
             if cls.subparser not in _subparsers:
-                parent_parser = argparse.ArgumentParser(add_help=False)    
-                p = subparsers.add_parser(cls.subparser,
-                            help = cls.subparser, parents=[parent_parser])
-                _subparsers[cls.subparser] = p.add_subparsers(title=cls.subparser,
-                        dest=cls.subparser)
+                try:
+                    description = _subparsers_description[cls.subparser]
+                except KeyError:
+                    description = cls.subparser
+                parent_parser = argparse.ArgumentParser(add_help=False)
+                p = subparsers.add_parser(cls.subparser, help=description,
+                                          description=description,
+                                          parents=[parent_parser])
+                _subparsers[cls.subparser] = p.add_subparsers(
+                    title=cls.subparser, dest=cls.subparser)
             sp = _subparsers[cls.subparser]
             for name in names:
-                sc = sp.add_parser(name, description = cls.description, 
-                                   help = cls.description)
+                sc = sp.add_parser(name, description=cls.description, 
+                                   help=cls.description)
                 sc.set_defaults(func=cls.run)
                 for arg in cls.args:
                     _add_arg(sc, arg)
@@ -1185,6 +1193,61 @@
             print()
             pprint.pprint(rv)
 
+
+class YTConfigGetCmd(YTCommand):
+    subparser = 'config'
+    name = 'get'
+    description = 'get a config value'
+    args = (dict(short='section', help='The section containing the option.'),
+            dict(short='option', help='The option to retrieve.'))
+    def __call__(self, args):
+        from yt.utilities.configure import get_config
+        print(get_config(args.section, args.option))
+
+
+class YTConfigSetCmd(YTCommand):
+    subparser = 'config'
+    name = 'set'
+    description = 'set a config value'
+    args = (dict(short='section', help='The section containing the option.'),
+            dict(short='option', help='The option to set.'),
+            dict(short='value', help='The value to set the option to.'))
+    def __call__(self, args):
+        from yt.utilities.configure import set_config
+        set_config(args.section, args.option, args.value)
+
+
+class YTConfigRemoveCmd(YTCommand):
+    subparser = 'config'
+    name = 'rm'
+    description = 'remove a config option'
+    args = (dict(short='section', help='The section containing the option.'),
+            dict(short='option', help='The option to remove.'))
+    def __call__(self, args):
+        from yt.utilities.configure import rm_config
+        rm_config(args.section, args.option)
+
+
+class YTConfigListCmd(YTCommand):
+    subparser = 'config'
+    name = 'list'
+    description = 'show the config content'
+    args = ()
+    def __call__(self, args):
+        from yt.utilities.configure import write_config
+        write_config(sys.stdout)
+
+
+class YTConfigMigrateCmd(YTCommand):
+    subparser = 'config'
+    name = 'migrate'
+    description = 'migrate old config file'
+    args = ()
+    def __call__(self, args):
+        from yt.utilities.configure import migrate_config
+        migrate_config()
+
+
 class YTSearchCmd(YTCommand):
     args = (dict(short="-o", longname="--output",
                  action="store", type=str,

diff -r 0191e92c97b3be82802261843695dceba948dc77 -r 676146ba9b5bebb15f0a252b0acb9710ad77c415 yt/utilities/tests/test_config.py
--- a/yt/utilities/tests/test_config.py
+++ b/yt/utilities/tests/test_config.py
@@ -12,7 +12,7 @@
 import os
 import sys
 import unittest
-import yt.utilities.configure
+import yt.utilities.command_line
 import yt.config
 from yt.config import \
     CURRENT_CONFIG_FILE, _OLD_CONFIG_FILE
@@ -59,14 +59,14 @@
 
 class TestYTConfig(unittest.TestCase):
     def _runYTConfig(self, args):
-        args = ['yt-config'] + args
+        args = ['yt', 'config'] + args
         retcode = 0
 
         with mock.patch.object(sys, 'argv', args),\
                 mock.patch('sys.exit', side_effect=SysExitException) as exit,\
                 captureOutput() as output:
             try:
-                yt.utilities.configure.main()
+                yt.utilities.command_line.run_main()
             except SysExitException:
                 args = exit.mock_calls[0][1]
                 retcode = args[0] if len(args) else 0


https://bitbucket.org/yt_analysis/yt/commits/62123be3ce1a/
Changeset:   62123be3ce1a
Branch:      yt
User:        xarthisius
Date:        2016-08-02 15:09:01+00:00
Summary:     Convert yt-config to yt's subparser (docs)
Affected #:  5 files

diff -r 676146ba9b5bebb15f0a252b0acb9710ad77c415 -r 62123be3ce1a97b16ef852dfa7859fccfbe055fa doc/source/developing/testing.rst
--- a/doc/source/developing/testing.rst
+++ b/doc/source/developing/testing.rst
@@ -290,7 +290,7 @@
 
 .. code-block:: none
 
-   $ yt-config set yt test_data_dir /Users/tomservo/src/yt-data
+   $ yt config set yt test_data_dir /Users/tomservo/src/yt-data
 
 More data will be added over time.  To run the answer tests, you must first
 generate a set of test answers locally on a "known good" revision, then update

diff -r 676146ba9b5bebb15f0a252b0acb9710ad77c415 -r 62123be3ce1a97b16ef852dfa7859fccfbe055fa doc/source/faq/index.rst
--- a/doc/source/faq/index.rst
+++ b/doc/source/faq/index.rst
@@ -441,7 +441,7 @@
 
 .. code-block:: bash
 
-   $ yt-config set yt loglevel 10  # This sets the log level to "DEBUG"
+   $ yt config set yt loglevel 10  # This sets the log level to "DEBUG"
 
 which would produce debug (as well as info, warning, and error) messages, or at runtime:
 

diff -r 676146ba9b5bebb15f0a252b0acb9710ad77c415 -r 62123be3ce1a97b16ef852dfa7859fccfbe055fa doc/source/reference/command-line.rst
--- a/doc/source/reference/command-line.rst
+++ b/doc/source/reference/command-line.rst
@@ -291,13 +291,13 @@
 Config helper
 ~~~~~~~~~~~~~
 
-The :code:`yt-config` command-line tool allows you to modify and access the yt's
+The :code:`yt config` command-line tool allows you to modify and access the yt's
 configuration without manually locating and opening the config file in an editor.
 To get a quick list of available commands, just type:
 
 .. code-block:: bash
 
-   yt-config -h
+   yt config -h
 
 This will print the list of available subcommands:
 
@@ -318,7 +318,7 @@
 
 .. code-block:: bash
 
-   yt-config migrate
+   yt config migrate
 
 that will copy your current config file to the new location and store a backup
 copy as ``$HOME/.yt/config.bak``.
@@ -330,7 +330,7 @@
 
 .. code-block:: bash
 
-   $ yt-config list
+   $ yt config list
    [yt]
    loglevel = 50
 
@@ -338,17 +338,17 @@
 
 .. code-block:: bash
 
-   $ yt-config get yt loglevel
+   $ yt config get yt loglevel
    50
 
 Changing a single config value:
 
 .. code-block:: bash
 
-   $ yt-config set yt loglevel 10
+   $ yt config set yt loglevel 10
 
 Removing a single config entry:
 
 .. code-block:: bash
 
-   $ yt-config rm yt loglevel
+   $ yt config rm yt loglevel

diff -r 676146ba9b5bebb15f0a252b0acb9710ad77c415 -r 62123be3ce1a97b16ef852dfa7859fccfbe055fa doc/source/reference/configuration.rst
--- a/doc/source/reference/configuration.rst
+++ b/doc/source/reference/configuration.rst
@@ -32,15 +32,15 @@
 This configuration file would set the logging threshold much lower, enabling
 much more voluminous output from yt.  Additionally, it increases the number of
 datasets tracked between instantiations of yt. The configuration file can be
-managed using the ``yt-config`` helper. It can list, add, modify and remove
+managed using the ``yt config`` helper. It can list, add, modify and remove
 options from the configuration file, e.g.:
 
 .. code-block:: none
 
-   $ yt-config -h
-   $ yt-config list
-   $ yt-config set yt loglevel 1
-   $ yt-config rm yt maximumstoreddatasets
+   $ yt config -h
+   $ yt config list
+   $ yt config set yt loglevel 1
+   $ yt config rm yt maximumstoreddatasets
 
 
 Configuration Options At Runtime

diff -r 676146ba9b5bebb15f0a252b0acb9710ad77c415 -r 62123be3ce1a97b16ef852dfa7859fccfbe055fa doc/source/sharing_data.rst
--- a/doc/source/sharing_data.rst
+++ b/doc/source/sharing_data.rst
@@ -39,7 +39,7 @@
 
 .. code-block:: none
 
-   $ yt-config set yt hub_api_key 3fd8de56c2884c13a2de4dd51a80974b
+   $ yt config set yt hub_api_key 3fd8de56c2884c13a2de4dd51a80974b
 
 Replace ``3fd8de56c2884c13a2de4dd51a80974b`` with your API key.
 


https://bitbucket.org/yt_analysis/yt/commits/2df706324d4a/
Changeset:   2df706324d4a
Branch:      yt
User:        xarthisius
Date:        2016-08-02 15:56:40+00:00
Summary:     Move hub commands to separate subparser
Affected #:  3 files

diff -r 62123be3ce1a97b16ef852dfa7859fccfbe055fa -r 2df706324d4a0de30c68bb8128c21ed7ad4d97dc doc/source/reference/command-line.rst
--- a/doc/source/reference/command-line.rst
+++ b/doc/source/reference/command-line.rst
@@ -222,23 +222,6 @@
 notebooks will be viewable online, and the appropriate URLs will be returned on
 the command line.
 
-
-hub_register
-++++++++++++
-
-This commands starts an interactive process of creating an account on the `yt
-hub <https://hub.yt/>`__. Please note that the yt Hub also supports multiple OAuth
-providers such as Google, Bitbucket and GitHub for authentication. 
-See :ref:`sharing-data` for more information.
-
-hubstart
-++++++++
-
-This command launches the Jupyter Notebook on the `yt hub <https://hub.yt>`__
-with a direct access to all the `example yt datasets
-<https://yt-project.org/data>`_. The appropriate URL allowing to access the
-Notebook will be return on the commandline.
-
 rpdb
 ++++
 
@@ -288,6 +271,37 @@
 can be used to remove it. This subcommand provides an easy way to send a delete
 request directly to the `imgur.com <http://imgur.com/>`_.
 
+Hub helper
+~~~~~~~~~~
+
+The :code:`yt hub` command-line tool allows to interact with the `yt hub
+<https://hub.yt>`__. Following subcommands are currently available:
+
+register
+++++++++
+
+This subcommands starts an interactive process of creating an account on the `yt
+hub <https://hub.yt/>`__. Please note that the yt Hub also supports multiple OAuth
+providers such as Google, Bitbucket and GitHub for authentication. 
+See :ref:`sharing-data` for more information.
+
+start
++++++
+
+This subcommand launches the Jupyter Notebook on the `yt Hub <https://hub.yt>`__
+with a chosen Hub folder mounted to the ``/data`` directory inside the notebook.
+If no path is given all the `example yt datasets
+<https://yt-project.org/data>`_ are mounted by default. The appropriate URL
+allowing to access the Notebook will be return on the commandline. 
+
+Example:
+
+.. code-block:: bash
+
+   $ yt hub start
+   $ yt hub start /user/xarthisius/Public
+
+
 Config helper
 ~~~~~~~~~~~~~
 

diff -r 62123be3ce1a97b16ef852dfa7859fccfbe055fa -r 2df706324d4a0de30c68bb8128c21ed7ad4d97dc doc/source/sharing_data.rst
--- a/doc/source/sharing_data.rst
+++ b/doc/source/sharing_data.rst
@@ -51,7 +51,7 @@
 
 .. code-block:: bash
 
-   $ yt hub_register
+   $ yt hub register
 
 This will walk you through the process of registering. You will need to supply
 a name, a username, a password and an email address. Apart from creating a new

diff -r 62123be3ce1a97b16ef852dfa7859fccfbe055fa -r 2df706324d4a0de30c68bb8128c21ed7ad4d97dc yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -138,7 +138,8 @@
 
 _subparsers = {None: subparsers}
 _subparsers_description = {
-    'config': 'Get and set configuration values for yt'
+    'config': 'Get and set configuration values for yt',
+    'hub': 'Interact with the yt Hub'
 }
 class YTCommandSubtype(type):
     def __init__(cls, name, b, d):
@@ -591,7 +592,8 @@
 
 
 class YTHubRegisterCmd(YTCommand):
-    name = "hub_register"
+    subparser = "hub"
+    name = "register"
     description = \
         """
         Register a user on the yt Hub: http://hub.yt/
@@ -848,24 +850,29 @@
         lo.main( None, download=args.number )
 
 class YTHubStartNotebook(YTCommand):
-    args = ()
+    args = (
+        dict(dest="folderId", default=ytcfg.get("yt", "hub_sandbox"),
+             nargs="?", 
+             help="(Optional) Hub folder to mount inside the Notebook"),
+    )
     description = \
         """
         Start the Jupyter Notebook on the yt Hub.
         """
-    name = "hubstart"
+    subparser = "hub"
+    name = "start"
     def __call__(self, args):
         gc = _get_girder_client()
 
         # TODO: should happen server-side
-        _id = gc._checkResourcePath(ytcfg.get("yt", "hub_sandbox"))
+        _id = gc._checkResourcePath(args.folderId)
 
         resp = gc.post("/notebook/{}".format(_id))
         try:
             print("Launched! Please visit this URL:")
             print("    https://tmpnb.hub.yt" + resp['url'])
             print()
-        except KeyError:
+        except (KeyError, TypeError):
             print("Something went wrong. The yt Hub responded with : ")
             print(resp)
 


https://bitbucket.org/yt_analysis/yt/commits/c60b2386d444/
Changeset:   c60b2386d444
Branch:      yt
User:        xarthisius
Date:        2016-08-02 17:16:24+00:00
Summary:     Add sphinx extension for automatic generation of 'command -h' blocks
Affected #:  3 files

diff -r 2df706324d4a0de30c68bb8128c21ed7ad4d97dc -r c60b2386d4447daa5e3d582724c3d048d18d404b doc/extensions/config_help.py
--- /dev/null
+++ b/doc/extensions/config_help.py
@@ -0,0 +1,34 @@
+import re
+import subprocess
+from docutils import statemachine
+from sphinx.util.compat import Directive
+
+def setup(app):
+    app.add_directive('config_help', GetConfigHelp)
+    setup.app = app
+    setup.config = app.config
+    setup.confdir = app.confdir
+
+    retdict = dict(
+        version='1.0',
+        parallel_read_safe=True,
+        parallel_write_safe=True
+    )
+
+    return retdict
+
+class GetConfigHelp(Directive):
+    required_arguments = 1
+    optional_arguments = 0
+    final_argument_whitespace = True
+
+    def run(self):
+        rst_file = self.state_machine.document.attributes['source']
+        data = subprocess.check_output(
+            self.arguments[0].split(" ") + ['-h']).decode('utf8').split('\n')
+        ind = next((i for i, val in enumerate(data)
+                    if re.match('\s{0,3}\{.*\}\s*$', val)))
+        lines = ['.. code-block:: none', ''] + data[ind + 1:]
+        self.state_machine.insert_input(
+            statemachine.string2lines("\n".join(lines)), rst_file)
+        return []

diff -r 2df706324d4a0de30c68bb8128c21ed7ad4d97dc -r c60b2386d4447daa5e3d582724c3d048d18d404b doc/source/conf.py
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -31,7 +31,8 @@
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
 extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx',
               'sphinx.ext.pngmath', 'sphinx.ext.viewcode',
-              'sphinx.ext.napoleon', 'yt_cookbook', 'yt_colormaps']
+              'sphinx.ext.napoleon', 'yt_cookbook', 'yt_colormaps',
+              'config_help']
 
 if not on_rtd:
     extensions.append('sphinx.ext.autosummary')

diff -r 2df706324d4a0de30c68bb8128c21ed7ad4d97dc -r c60b2386d4447daa5e3d582724c3d048d18d404b doc/source/reference/command-line.rst
--- a/doc/source/reference/command-line.rst
+++ b/doc/source/reference/command-line.rst
@@ -54,34 +54,7 @@
 
 This will print the list of available subcommands,
 
-.. code-block:: bash
-
-    help                Print help message
-    bugreport           Report a bug in yt
-    hub_register        Register a user on the yt Hub: https://hub.yt/
-    instinfo            Get some information about the yt installation
-    version             Get some information about the yt installation (this
-                        is an alias for instinfo).
-    load                Load a single dataset into an IPython instance
-    mapserver           Serve a plot in a GMaps-style interface
-    pastebin            Post a script to an anonymous pastebin
-    pastebin_grab       Print an online pastebin to STDOUT for local use.
-    hubstart            Start the Jupyter Notebook on the yt Hub. 
-    upload_notebook     Upload an IPython Notebook to the yt Hub.
-    plot                Create a set of images
-    rpdb                Connect to a currently running (on localhost) rpd
-                        session. Commands run with --rpdb will trigger an rpdb
-                        session with any uncaught exceptions.
-    notebook            Start the Jupyter Notebook locally.
-    stats               Print stats and max/min value of a given field (if
-                        requested), for one or more datasets (default field is
-                        Density)
-    update              Update the yt installation to the most recent version
-    delete_image        Delete image from imgur.com.
-    upload_image        Upload an image to imgur.com. Must be PNG.
-    search              Attempt to find outputs that yt can recognize in
-                        directories.
-
+.. config_help:: yt
 
 To execute any such function, simply run:
 
@@ -277,10 +250,12 @@
 The :code:`yt hub` command-line tool allows to interact with the `yt hub
 <https://hub.yt>`__. Following subcommands are currently available:
 
+.. config_help:: yt hub
+
 register
 ++++++++
 
-This subcommands starts an interactive process of creating an account on the `yt
+This subcommand starts an interactive process of creating an account on the `yt
 hub <https://hub.yt/>`__. Please note that the yt Hub also supports multiple OAuth
 providers such as Google, Bitbucket and GitHub for authentication. 
 See :ref:`sharing-data` for more information.
@@ -315,13 +290,7 @@
 
 This will print the list of available subcommands:
 
-.. code-block:: bash
-
-	get                 get a config value
-	set                 set a config value
-	rm                  remove a config option
-	migrate             migrate old config file
-	list                show all config values
+.. config_help:: yt config
 
 Since the yt version 3.3.2, the previous location of the configuration file
 (``$HOME/.yt/config``) has been deprecated in favor of a location adhering to the


https://bitbucket.org/yt_analysis/yt/commits/c96b519d5431/
Changeset:   c96b519d5431
Branch:      yt
User:        xarthisius
Date:        2016-08-02 17:50:30+00:00
Summary:     Expand docs describing how to obtain an API Key for the Hub
Affected #:  7 files

diff -r c60b2386d4447daa5e3d582724c3d048d18d404b -r c96b519d543114dab070a49ef1ab70522aa55628 doc/source/_static/apiKey01.jpg
Binary file doc/source/_static/apiKey01.jpg has changed

diff -r c60b2386d4447daa5e3d582724c3d048d18d404b -r c96b519d543114dab070a49ef1ab70522aa55628 doc/source/_static/apiKey02.jpg
Binary file doc/source/_static/apiKey02.jpg has changed

diff -r c60b2386d4447daa5e3d582724c3d048d18d404b -r c96b519d543114dab070a49ef1ab70522aa55628 doc/source/_static/apiKey03.jpg
Binary file doc/source/_static/apiKey03.jpg has changed

diff -r c60b2386d4447daa5e3d582724c3d048d18d404b -r c96b519d543114dab070a49ef1ab70522aa55628 doc/source/_static/apiKey04.jpg
Binary file doc/source/_static/apiKey04.jpg has changed

diff -r c60b2386d4447daa5e3d582724c3d048d18d404b -r c96b519d543114dab070a49ef1ab70522aa55628 doc/source/reference/command-line.rst
--- a/doc/source/reference/command-line.rst
+++ b/doc/source/reference/command-line.rst
@@ -258,7 +258,7 @@
 This subcommand starts an interactive process of creating an account on the `yt
 hub <https://hub.yt/>`__. Please note that the yt Hub also supports multiple OAuth
 providers such as Google, Bitbucket and GitHub for authentication. 
-See :ref:`sharing-data` for more information.
+See :ref:`hub-APIkey` for more information.
 
 start
 +++++

diff -r c60b2386d4447daa5e3d582724c3d048d18d404b -r c96b519d543114dab070a49ef1ab70522aa55628 doc/source/sharing_data.rst
--- a/doc/source/sharing_data.rst
+++ b/doc/source/sharing_data.rst
@@ -27,21 +27,48 @@
 .. note:: Working with the Hub requires additional dependencies to be installed.
           You can obtain them by running: ``pip install yt[hub]``. 
 
-Obtaining API key
------------------
+.. _hub-APIkey:
+
+Obtaining an API key
+--------------------
 
 In order to interact with the yt Hub, you need to obtain API key, which is
 available only for authenticated users. You can `log into
 <https://girder.hub.yt/#?dialog=login>`_ the Hub using your Google, GitHub or
-Bitbucket account. After you log in, API key can be generated in your account
-settings view, which can be accessed through dropdown menu in the upper right
-corner. After you have gotten your API key, update your config file:
+Bitbucket account. After you log in, an API key can be generated under the *My
+account* page, which can be accessed through dropdown menu in the upper right
+corner. 
+
+.. image:: _static/apiKey01.jpg
+   :width: 50 %
+
+Select the *API keys* tab and press *Create new key* button:
+
+.. image:: _static/apiKey02.jpg
+   :width: 50 %
+
+By convention, the *Name* field of API keys can be used to specify what
+application is making use of the key in a human-readable way e.g. ``yt
+command``, although you may name your key however you want.
+
+.. image:: _static/apiKey03.jpg
+   :width: 50 %
+
+After the API Key is created you can obtain it by clicking *show* link:
+
+.. image:: _static/apiKey04.jpg
+   :width: 50 %
+
+For more information about API keys please see `this document
+<http://girder.readthedocs.io/en/latest/user-guide.html?highlight=API%20keys#api-keys>`__.
+
+After you have gotten your API key, update your config file:
 
 .. code-block:: none
 
-   $ yt config set yt hub_api_key 3fd8de56c2884c13a2de4dd51a80974b
+   $ yt config set yt hub_api_key 3fd1de56c2114c13a2de4dd51g10974b
 
-Replace ``3fd8de56c2884c13a2de4dd51a80974b`` with your API key.
+Replace ``3fd1de56c2114c13a2de4dd51g10974b`` with your API key.
 
 Registering a User
 ^^^^^^^^^^^^^^^^^^

diff -r c60b2386d4447daa5e3d582724c3d048d18d404b -r c96b519d543114dab070a49ef1ab70522aa55628 yt/utilities/configure.py
--- a/yt/utilities/configure.py
+++ b/yt/utilities/configure.py
@@ -42,7 +42,7 @@
     CONFIG.read(_OLD_CONFIG_FILE)
     print("Writing a new config file to: {}".format(CURRENT_CONFIG_FILE))
     write_config()
-    print("Backing up the old config file: {}".format(_OLD_CONFIG_FILE))
+    print("Backing up the old config file: {}.bak".format(_OLD_CONFIG_FILE))
     os.rename(_OLD_CONFIG_FILE, _OLD_CONFIG_FILE + '.bak')
 
 


https://bitbucket.org/yt_analysis/yt/commits/ab2c205b0fdc/
Changeset:   ab2c205b0fdc
Branch:      yt
User:        xarthisius
Date:        2016-08-03 18:28:36+00:00
Summary:     Fix prepositions and docstrings
Affected #:  3 files

diff -r c96b519d543114dab070a49ef1ab70522aa55628 -r ab2c205b0fdca689b23cf94ee26a0285bb670cc5 doc/source/reference/command-line.rst
--- a/doc/source/reference/command-line.rst
+++ b/doc/source/reference/command-line.rst
@@ -248,7 +248,7 @@
 ~~~~~~~~~~
 
 The :code:`yt hub` command-line tool allows to interact with the `yt hub
-<https://hub.yt>`__. Following subcommands are currently available:
+<https://hub.yt>`__. The following subcommands are currently available:
 
 .. config_help:: yt hub
 
@@ -267,7 +267,7 @@
 with a chosen Hub folder mounted to the ``/data`` directory inside the notebook.
 If no path is given all the `example yt datasets
 <https://yt-project.org/data>`_ are mounted by default. The appropriate URL
-allowing to access the Notebook will be return on the commandline. 
+allowing to access the Notebook will be returned on the commandline. 
 
 Example:
 
@@ -280,7 +280,7 @@
 Config helper
 ~~~~~~~~~~~~~
 
-The :code:`yt config` command-line tool allows you to modify and access the yt's
+The :code:`yt config` command-line tool allows you to modify and access yt's
 configuration without manually locating and opening the config file in an editor.
 To get a quick list of available commands, just type:
 

diff -r c96b519d543114dab070a49ef1ab70522aa55628 -r ab2c205b0fdca689b23cf94ee26a0285bb670cc5 doc/source/sharing_data.rst
--- a/doc/source/sharing_data.rst
+++ b/doc/source/sharing_data.rst
@@ -36,8 +36,8 @@
 available only for authenticated users. You can `log into
 <https://girder.hub.yt/#?dialog=login>`_ the Hub using your Google, GitHub or
 Bitbucket account. After you log in, an API key can be generated under the *My
-account* page, which can be accessed through dropdown menu in the upper right
-corner. 
+account* page, which can be accessed through the dropdown menu in the upper
+right corner. 
 
 .. image:: _static/apiKey01.jpg
    :width: 50 %

diff -r c96b519d543114dab070a49ef1ab70522aa55628 -r ab2c205b0fdca689b23cf94ee26a0285bb670cc5 yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -107,7 +107,7 @@
     msg = (
         "The configuration file {} is deprecated. "
         "Please migrate your config to {} by running: "
-        "'yt-config migrate'"
+        "'yt config migrate'"
     )
     warnings.warn(msg.format(_OLD_CONFIG_FILE, CURRENT_CONFIG_FILE))
 


https://bitbucket.org/yt_analysis/yt/commits/42d65f24f2d8/
Changeset:   42d65f24f2d8
Branch:      yt
User:        MatthewTurk
Date:        2016-08-09 16:13:24+00:00
Summary:     Merged in xarthisius/yt (pull request #2289)

Update config file handling and 'yt hub_register/upload_notebook/hubstart'
Affected #:  20 files

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 doc/extensions/config_help.py
--- /dev/null
+++ b/doc/extensions/config_help.py
@@ -0,0 +1,34 @@
+import re
+import subprocess
+from docutils import statemachine
+from sphinx.util.compat import Directive
+
+def setup(app):
+    app.add_directive('config_help', GetConfigHelp)
+    setup.app = app
+    setup.config = app.config
+    setup.confdir = app.confdir
+
+    retdict = dict(
+        version='1.0',
+        parallel_read_safe=True,
+        parallel_write_safe=True
+    )
+
+    return retdict
+
+class GetConfigHelp(Directive):
+    required_arguments = 1
+    optional_arguments = 0
+    final_argument_whitespace = True
+
+    def run(self):
+        rst_file = self.state_machine.document.attributes['source']
+        data = subprocess.check_output(
+            self.arguments[0].split(" ") + ['-h']).decode('utf8').split('\n')
+        ind = next((i for i, val in enumerate(data)
+                    if re.match('\s{0,3}\{.*\}\s*$', val)))
+        lines = ['.. code-block:: none', ''] + data[ind + 1:]
+        self.state_machine.insert_input(
+            statemachine.string2lines("\n".join(lines)), rst_file)
+        return []

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 doc/source/_static/apiKey01.jpg
Binary file doc/source/_static/apiKey01.jpg has changed

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 doc/source/_static/apiKey02.jpg
Binary file doc/source/_static/apiKey02.jpg has changed

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 doc/source/_static/apiKey03.jpg
Binary file doc/source/_static/apiKey03.jpg has changed

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 doc/source/_static/apiKey04.jpg
Binary file doc/source/_static/apiKey04.jpg has changed

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 doc/source/conf.py
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -31,7 +31,8 @@
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
 extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx',
               'sphinx.ext.pngmath', 'sphinx.ext.viewcode',
-              'sphinx.ext.napoleon', 'yt_cookbook', 'yt_colormaps']
+              'sphinx.ext.napoleon', 'yt_cookbook', 'yt_colormaps',
+              'config_help']
 
 if not on_rtd:
     extensions.append('sphinx.ext.autosummary')

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 doc/source/cookbook/yt_gadget_owls_analysis.ipynb
--- a/doc/source/cookbook/yt_gadget_owls_analysis.ipynb
+++ b/doc/source/cookbook/yt_gadget_owls_analysis.ipynb
@@ -20,7 +20,7 @@
    "source": [
     "The first thing you will need to run these examples is a working installation of yt.  The author or these examples followed the instructions under \"Get yt: from source\" at http://yt-project.org/ to install an up to date development version of yt.\n",
     "\n",
-    "Next you should set the default ``test_data_dir`` in the ``.yt/config`` file in your home directory.  Note that you may have to create the directory and file if it doesn't exist already.\n",
+    "Next you should set the default ``test_data_dir`` in the ``~/.config/yt/ytrc`` file in your home directory.  Note that you may have to create the directory and file if it doesn't exist already.\n",
     "\n",
     "> [yt]\n",
     "\n",

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 doc/source/developing/testing.rst
--- a/doc/source/developing/testing.rst
+++ b/doc/source/developing/testing.rst
@@ -285,15 +285,12 @@
 
 These datasets are available at http://yt-project.org/data/.
 
-Next, modify the file ``~/.yt/config`` to include a section ``[yt]``
-with the parameter ``test_data_dir``.  Set this to point to the
-directory with the test data you want to test with.  Here is an example
-config file:
+Next, add the config parameter ``test_data_dir`` pointing to 
+directory with the test data you want to test with, e.g.:
 
 .. code-block:: none
 
-   [yt]
-   test_data_dir = /Users/tomservo/src/yt-data
+   $ yt config set yt test_data_dir /Users/tomservo/src/yt-data
 
 More data will be added over time.  To run the answer tests, you must first
 generate a set of test answers locally on a "known good" revision, then update
@@ -313,7 +310,7 @@
 This command will create a set of local answers from the tipsy frontend tests
 and store them in ``$HOME/Documents/test`` (this can but does not have to be the
 same directory as the ``test_data_dir`` configuration variable defined in your
-``.yt/config`` file) in a file named ``local-tipsy``. To run the tipsy
+``~/.config/yt/ytrc`` file) in a file named ``local-tipsy``. To run the tipsy
 frontend's answer tests using a different yt changeset, update to that
 changeset, recompile if necessary, and run the tests using the following
 command:

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 doc/source/faq/index.rst
--- a/doc/source/faq/index.rst
+++ b/doc/source/faq/index.rst
@@ -388,10 +388,10 @@
 To make things easier to load these sample datasets, you can add the parent
 directory to your downloaded sample data to your *yt path*.
 If you set the option ``test_data_dir``, in the section ``[yt]``,
-in ``~/.yt/config``, yt will search this path for them.
+in ``~/.config/yt/ytrc``, yt will search this path for them.
 
 This means you can download these datasets to ``/big_drive/data_for_yt`` , add
-the appropriate item to ``~/.yt/config``, and no matter which directory you are
+the appropriate item to ``~/.config/yt/ytrc``, and no matter which directory you are
 in when running yt, it will also check in *that* directory.
 
 
@@ -437,12 +437,11 @@
 hand, you may want it to output a lot more, since you can't figure out exactly what's going
 wrong, and you want to output some debugging information. The yt log level can be
 changed using the :ref:`configuration-file`, either by setting it in the
-``$HOME/.yt/config`` file:
+``$HOME/.config/yt/ytrc`` file:
 
 .. code-block:: bash
 
-   [yt]
-   loglevel = 10 # This sets the log level to "DEBUG"
+   $ yt config set yt loglevel 10  # This sets the log level to "DEBUG"
 
 which would produce debug (as well as info, warning, and error) messages, or at runtime:
 

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -133,6 +133,16 @@
      <tr valign="top"><td width="25%"><p>
+           <a href="sharing_data.html">Sharing Data</a>
+         </p>
+       </td>
+       <td width="75%">
+         <p class="linkdescr">The yt Hub</p>
+       </td>
+     </tr>
+     <tr valign="top">
+       <td width="25%">
+         <p><a href="reference/index.html">Reference Materials</a></p></td>
@@ -185,6 +195,7 @@
    analyzing/analysis_modules/index
    examining/index
    developing/index
+   sharing_data
    reference/index
    faq/index
    Getting Help <help/index>

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 doc/source/reference/command-line.rst
--- a/doc/source/reference/command-line.rst
+++ b/doc/source/reference/command-line.rst
@@ -54,35 +54,7 @@
 
 This will print the list of available subcommands,
 
-.. code-block:: bash
-
-    help                Print help message
-    bootstrap_dev       Bootstrap a yt development environment
-    bugreport           Report a bug in yt
-    hub_register        Register a user on the Hub: http://hub.yt-project.org/
-    hub_submit          Submit a mercurial repository to the yt Hub
-                        (http://hub.yt-project.org/), creating a BitBucket
-                        repo in the process if necessary.
-    instinfo            Get some information about the yt installation
-    version             Get some information about the yt installation (this
-                        is an alias for instinfo).
-    load                Load a single dataset into an IPython instance
-    mapserver           Serve a plot in a GMaps-style interface
-    pastebin            Post a script to an anonymous pastebin
-    pastebin_grab       Print an online pastebin to STDOUT for local use.
-    upload_notebook     Upload an IPython notebook to hub.yt-project.org.
-    plot                Create a set of images
-    rpdb                Connect to a currently running (on localhost) rpd
-                        session. Commands run with --rpdb will trigger an rpdb
-                        session with any uncaught exceptions.
-    notebook            Run the IPython Notebook
-    stats               Print stats and max/min value of a given field (if
-                        requested), for one or more datasets (default field is
-                        Density)
-    update              Update the yt installation to the most recent version
-    delete_image        Delete image from imgur.com.
-    upload_image        Upload an image to imgur.com. Must be PNG.
-
+.. config_help:: yt
 
 To execute any such function, simply run:
 
@@ -217,13 +189,12 @@
 
 This command will accept the filename of a ``.ipynb`` file (generated from an
 IPython notebook session) and upload it to the `yt hub
-<http://hub.yt-project.org/>` where others will be able to view it, and
+<https://hub.yt/>`__ where others will be able to view it, and
 download it.  This is an easy method for recording a sequence of commands,
 their output, narrative information, and then sharing that with others.  These
 notebooks will be viewable online, and the appropriate URLs will be returned on
 the command line.
 
-
 rpdb
 ++++
 
@@ -272,3 +243,95 @@
 The image uploaded using ``upload_image`` is assigned with a unique hash that
 can be used to remove it. This subcommand provides an easy way to send a delete
 request directly to the `imgur.com <http://imgur.com/>`_.
+
+Hub helper
+~~~~~~~~~~
+
+The :code:`yt hub` command-line tool allows to interact with the `yt hub
+<https://hub.yt>`__. The following subcommands are currently available:
+
+.. config_help:: yt hub
+
+register
+++++++++
+
+This subcommand starts an interactive process of creating an account on the `yt
+hub <https://hub.yt/>`__. Please note that the yt Hub also supports multiple OAuth
+providers such as Google, Bitbucket and GitHub for authentication. 
+See :ref:`hub-APIkey` for more information.
+
+start
++++++
+
+This subcommand launches the Jupyter Notebook on the `yt Hub <https://hub.yt>`__
+with a chosen Hub folder mounted to the ``/data`` directory inside the notebook.
+If no path is given all the `example yt datasets
+<https://yt-project.org/data>`_ are mounted by default. The appropriate URL
+allowing to access the Notebook will be returned on the commandline. 
+
+Example:
+
+.. code-block:: bash
+
+   $ yt hub start
+   $ yt hub start /user/xarthisius/Public
+
+
+Config helper
+~~~~~~~~~~~~~
+
+The :code:`yt config` command-line tool allows you to modify and access yt's
+configuration without manually locating and opening the config file in an editor.
+To get a quick list of available commands, just type:
+
+.. code-block:: bash
+
+   yt config -h
+
+This will print the list of available subcommands:
+
+.. config_help:: yt config
+
+Since the yt version 3.3.2, the previous location of the configuration file
+(``$HOME/.yt/config``) has been deprecated in favor of a location adhering to the
+`XDG Base Directory Specification
+<https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html>`_.
+(``$XDG_HOME_CONFIG/yt/ytrc``). In order to perform an automatic migration of
+the old config, you are encouraged to run:
+
+.. code-block:: bash
+
+   yt config migrate
+
+that will copy your current config file to the new location and store a backup
+copy as ``$HOME/.yt/config.bak``.
+
+Examples
+++++++++
+
+Listing current content of the config file:
+
+.. code-block:: bash
+
+   $ yt config list
+   [yt]
+   loglevel = 50
+
+Obtaining a single config value by name:
+
+.. code-block:: bash
+
+   $ yt config get yt loglevel
+   50
+
+Changing a single config value:
+
+.. code-block:: bash
+
+   $ yt config set yt loglevel 10
+
+Removing a single config entry:
+
+.. code-block:: bash
+
+   $ yt config rm yt loglevel

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 doc/source/reference/configuration.rst
--- a/doc/source/reference/configuration.rst
+++ b/doc/source/reference/configuration.rst
@@ -18,9 +18,9 @@
 Configuration File Format
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-yt will look for and recognize the file ``$HOME/.yt/config`` as a configuration
+yt will look for and recognize the file ``$HOME/.config/yt/ytrc`` as a configuration
 file, containing several options that can be modified and adjusted to control
-runtime behavior.  For example, a sample ``$HOME/.yt/config`` file could look
+runtime behavior.  For example, a sample ``$HOME/.config/yt/ytrc`` file could look
 like:
 
 .. code-block:: none
@@ -31,7 +31,17 @@
 
 This configuration file would set the logging threshold much lower, enabling
 much more voluminous output from yt.  Additionally, it increases the number of
-datasets tracked between instantiations of yt.
+datasets tracked between instantiations of yt. The configuration file can be
+managed using the ``yt config`` helper. It can list, add, modify and remove
+options from the configuration file, e.g.:
+
+.. code-block:: none
+
+   $ yt config -h
+   $ yt config list
+   $ yt config set yt loglevel 1
+   $ yt config rm yt maximumstoreddatasets
+
 
 Configuration Options At Runtime
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 doc/source/sharing_data.rst
--- /dev/null
+++ b/doc/source/sharing_data.rst
@@ -0,0 +1,117 @@
+.. _sharing-data:
+
+The yt Hub
+==========
+
+.. contents::
+   :depth: 2
+   :local:
+   :backlinks: none
+
+What is the yt Hub?
+-------------------
+
+The yt data Hub is a mechanism by which images, data objects and projects can be
+shared with other people. For instance, one can upload a dataset and allow other
+people to remotely analyze it with a jupyter notebook or upload notebooks and
+view them from any web browser.
+
+.. note:: All items posted on the hub are public!
+
+Over time, more widgets will be added, and more datatypes will be able to be
+uploaded.  If you are interested in adding more ways of sharing data, please
+email the developers' list.  We would like to add support for 3D widgets such
+as isocontours as well as interactive binning and rebinning of data from yt
+data objects, to be displayed as phase plots and profiles.
+
+.. note:: Working with the Hub requires additional dependencies to be installed.
+          You can obtain them by running: ``pip install yt[hub]``. 
+
+.. _hub-APIkey:
+
+Obtaining an API key
+--------------------
+
+In order to interact with the yt Hub, you need to obtain API key, which is
+available only for authenticated users. You can `log into
+<https://girder.hub.yt/#?dialog=login>`_ the Hub using your Google, GitHub or
+Bitbucket account. After you log in, an API key can be generated under the *My
+account* page, which can be accessed through the dropdown menu in the upper
+right corner. 
+
+.. image:: _static/apiKey01.jpg
+   :width: 50 %
+
+Select the *API keys* tab and press *Create new key* button:
+
+.. image:: _static/apiKey02.jpg
+   :width: 50 %
+
+By convention, the *Name* field of API keys can be used to specify what
+application is making use of the key in a human-readable way e.g. ``yt
+command``, although you may name your key however you want.
+
+.. image:: _static/apiKey03.jpg
+   :width: 50 %
+
+After the API Key is created you can obtain it by clicking *show* link:
+
+.. image:: _static/apiKey04.jpg
+   :width: 50 %
+
+For more information about API keys please see `this document
+<http://girder.readthedocs.io/en/latest/user-guide.html?highlight=API%20keys#api-keys>`__.
+
+After you have gotten your API key, update your config file:
+
+.. code-block:: none
+
+   $ yt config set yt hub_api_key 3fd1de56c2114c13a2de4dd51g10974b
+
+Replace ``3fd1de56c2114c13a2de4dd51g10974b`` with your API key.
+
+Registering a User
+^^^^^^^^^^^^^^^^^^
+
+If you do not wish to use OAuth authentication, you can create a Hub account
+using ``yt`` command. To register a user:
+
+.. code-block:: bash
+
+   $ yt hub register
+
+This will walk you through the process of registering. You will need to supply
+a name, a username, a password and an email address. Apart from creating a new
+user account, it will also generate an API key and append it to the yt's config
+file.  At this point, you're ready to go!
+
+What Can Be Uploaded
+--------------------
+
+Currently, the yt hub can accept these types of data:
+
+ * Raw data files, scripts.
+ * IPython notebooks: these are stored on the hub and are made available for
+   download and via the IPython `nbviewer <http://nbviewer.ipython.org/>`_
+   service.
+
+How to Upload Data
+------------------
+
+Uploading data can be performed using the ``girder-cli`` command tool or
+directly via the web interface. Please refer to ``girder-cli`` `documentation page
+<http://girder.readthedocs.io/en/latest/python-client.html>`_ for additional
+information.
+
+Uploading Notebooks
+^^^^^^^^^^^^^^^^^^^
+
+Notebooks can be uploaded from the bash command line:
+
+.. code-block:: bash
+
+   yt upload_notebook notebook_file.ipynb
+
+After the notebook is finished uploading, yt will print a link to the raw
+notebook as well as an nbviewer link to the same notebook.  Your notebooks will
+be stored under your hub Public directory.

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 doc/source/visualizing/sketchfab.rst
--- a/doc/source/visualizing/sketchfab.rst
+++ b/doc/source/visualizing/sketchfab.rst
@@ -105,7 +105,7 @@
 but it requires that you get an API key first.  You can get this API key by
 creating an account and then going to your "dashboard," where it will be listed
 on the right hand side.  Once you've obtained it, put it into your
-``~/.yt/config`` file under the heading ``[yt]`` as the variable
+``~/.config/yt/ytrc`` file under the heading ``[yt]`` as the variable
 ``sketchfab_api_key``.  If you don't want to do this, you can also supply it as
 an argument to the function ``export_sketchfab``.
 

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 setup.py
--- a/setup.py
+++ b/setup.py
@@ -380,6 +380,9 @@
         'IPython',
         'cython',
     ],
+    extras_require = {
+        'hub':  ["girder_client"]
+    },
     cmdclass={'sdist': sdist, 'build_ext': build_ext, 'build_py': build_py},
     author="The yt project",
     author_email="yt-dev at lists.spacepope.org",

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -16,6 +16,7 @@
 #-----------------------------------------------------------------------------
 
 import os
+import warnings
 from yt.extern.six.moves import configparser
 
 ytcfg_defaults = dict(
@@ -48,8 +49,9 @@
     test_storage_dir = '/does/not/exist',
     test_data_dir = '/does/not/exist',
     enzo_db = '',
-    hub_url = 'https://hub.yt-project.org/upload',
+    hub_url = 'https://girder.hub.yt/api/v1',
     hub_api_key = '',
+    hub_sandbox = '/collection/yt_sandbox/data',
     notebook_password = '',
     answer_testing_tolerance = '3',
     answer_testing_bitwise = 'False',
@@ -67,20 +69,28 @@
     default_colormap = 'arbre',
     ray_tracing_engine = 'embree',
     )
+
+CONFIG_DIR = os.environ.get(
+    'XDG_CONFIG_HOME', os.path.join(os.path.expanduser('~'), '.config', 'yt'))
+if not os.path.exists(CONFIG_DIR):
+    os.makedirs(CONFIG_DIR)
+
+CURRENT_CONFIG_FILE = os.path.join(CONFIG_DIR, 'ytrc')
+_OLD_CONFIG_FILE = os.path.join(os.path.expanduser('~'), '.yt', 'config')
+
 # Here is the upgrade.  We're actually going to parse the file in its entirety
 # here.  Then, if it has any of the Forbidden Sections, it will be rewritten
 # without them.
 
-__fn = os.path.expanduser("~/.yt/config")
-if os.path.exists(__fn):
-    f = open(__fn).read()
+if os.path.exists(_OLD_CONFIG_FILE):
+    f = open(_OLD_CONFIG_FILE).read()
     if any(header in f for header in ["[lagos]","[raven]","[fido]","[enki]"]):
         print("***********************************************************")
         print("* Upgrading configuration file to new format; saving old. *")
         print("***********************************************************")
         # This is of the old format
         cp = configparser.ConfigParser()
-        cp.read(__fn)
+        cp.read(_OLD_CONFIG_FILE)
         # NOTE: To avoid having the 'DEFAULT' section here,
         # we are not passing in ytcfg_defaults to the constructor.
         new_cp = configparser.ConfigParser()
@@ -91,16 +101,21 @@
                 if option.lower() in ytcfg_defaults:
                     new_cp.set("yt", option, cp.get(section, option))
                     print("Setting %s to %s" % (option, cp.get(section, option)))
-        open(__fn + ".old", "w").write(f)
-        new_cp.write(open(__fn, "w"))
-# Pathological check for Kraken
-#elif os.path.exists("~/"):
-#    if not os.path.exists("~/.yt"):
-#            print "yt is creating a new directory, ~/.yt ."
-#            os.mkdir(os.path.exists("~/.yt/"))
-#    # Now we can read in and write out ...
-#    new_cp = configparser.ConfigParser(ytcfg_defaults)
-#    new_cp.write(__fn)
+        open(_OLD_CONFIG_FILE + ".old", "w").write(f)
+        new_cp.write(open(_OLD_CONFIG_FILE, "w"))
+
+    msg = (
+        "The configuration file {} is deprecated. "
+        "Please migrate your config to {} by running: "
+        "'yt config migrate'"
+    )
+    warnings.warn(msg.format(_OLD_CONFIG_FILE, CURRENT_CONFIG_FILE))
+
+if not os.path.exists(CURRENT_CONFIG_FILE):
+    cp = configparser.ConfigParser()
+    cp.add_section("yt")
+    with open(CURRENT_CONFIG_FILE, 'w') as new_cfg:
+        cp.write(new_cfg)
 
 class YTConfigParser(configparser.ConfigParser):
     def __setitem__(self, key, val):
@@ -108,12 +123,8 @@
     def __getitem__(self, key):
         self.get(key[0], key[1])
 
-if os.path.exists(os.path.expanduser("~/.yt/config")):
-    ytcfg = YTConfigParser(ytcfg_defaults)
-    ytcfg.read(['yt.cfg', os.path.expanduser('~/.yt/config')])
-else:
-    ytcfg = YTConfigParser(ytcfg_defaults)
-    ytcfg.read(['yt.cfg'])
+ytcfg = YTConfigParser(ytcfg_defaults)
+ytcfg.read([_OLD_CONFIG_FILE, CURRENT_CONFIG_FILE, 'yt.cfg'])
 if not ytcfg.has_section("yt"):
     ytcfg.add_section("yt")
 

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -26,7 +26,7 @@
 import json
 import pprint
 
-from yt.config import ytcfg
+from yt.config import ytcfg, CURRENT_CONFIG_FILE
 ytcfg["yt","__command_line"] = "True"
 from yt.startup_tasks import parser, subparsers
 from yt.funcs import \
@@ -39,11 +39,13 @@
     enable_plugins
 from yt.extern.six import add_metaclass, string_types
 from yt.extern.six.moves import urllib, input
+from yt.extern.six.moves.urllib.parse import urlparse
 from yt.convenience import load
 from yt.visualization.plot_window import \
     SlicePlot, \
     ProjectionPlot
 from yt.utilities.metadata import get_metadata
+from yt.utilities.configure import set_config
 from yt.utilities.exceptions import \
     YTOutputNotIdentified, YTFieldNotParseable
 
@@ -117,16 +119,48 @@
         print("Changeset = %s" % vstring.strip().decode("utf-8"))
     print("---")
     return vstring
+    
 
+def _get_girder_client():
+    try:
+        import girder_client
+    except ImportError:
+        print("this command requires girder_client to be installed")
+        print("Please install them using your python package manager, e.g.:")
+        print("   pip install girder_client --user")
+        exit()
+
+    hub_url = urlparse(ytcfg.get("yt", "hub_url"))
+    gc = girder_client.GirderClient(apiUrl=hub_url.geturl())
+    gc.authenticate(apiKey=ytcfg.get("yt", "hub_api_key"))
+    return gc
+
+
+_subparsers = {None: subparsers}
+_subparsers_description = {
+    'config': 'Get and set configuration values for yt',
+    'hub': 'Interact with the yt Hub'
+}
 class YTCommandSubtype(type):
     def __init__(cls, name, b, d):
         type.__init__(cls, name, b, d)
         if cls.name is not None:
             names = ensure_list(cls.name)
+            if cls.subparser not in _subparsers:
+                try:
+                    description = _subparsers_description[cls.subparser]
+                except KeyError:
+                    description = cls.subparser
+                parent_parser = argparse.ArgumentParser(add_help=False)
+                p = subparsers.add_parser(cls.subparser, help=description,
+                                          description=description,
+                                          parents=[parent_parser])
+                _subparsers[cls.subparser] = p.add_subparsers(
+                    title=cls.subparser, dest=cls.subparser)
+            sp = _subparsers[cls.subparser]
             for name in names:
-                sc = subparsers.add_parser(name,
-                    description = cls.description,
-                    help = cls.description)
+                sc = sp.add_parser(name, description=cls.description, 
+                                   help=cls.description)
                 sc.set_defaults(func=cls.run)
                 for arg in cls.args:
                     _add_arg(sc, arg)
@@ -138,6 +172,7 @@
     description = ""
     aliases = ()
     ndatasets = 1
+    subparser = None
 
     @classmethod
     def run(cls, args):
@@ -557,25 +592,27 @@
 
 
 class YTHubRegisterCmd(YTCommand):
-    name = "hub_register"
+    subparser = "hub"
+    name = "register"
     description = \
         """
-        Register a user on the Hub: http://hub.yt-project.org/
+        Register a user on the yt Hub: http://hub.yt/
         """
     def __call__(self, args):
-        # We need these pieces of information:
-        #   1. Name
-        #   2. Email
-        #   3. Username
-        #   4. Password (and password2)
-        #   5. (optional) URL
-        #   6. "Secret" key to make it epsilon harder for spammers
-        if ytcfg.get("yt","hub_api_key") != "":
+        try:
+            import requests
+        except ImportError:
+            print("yt {} requires requests to be installed".format(self.name))
+            print("Please install them using your python package manager, e.g.:")
+            print("   pip install requests --user")
+            exit()
+        if ytcfg.get("yt", "hub_api_key") != "":
             print("You seem to already have an API key for the hub in")
-            print("~/.yt/config .  Delete this if you want to force a")
+            print("{} . Delete this if you want to force a".format(CURRENT_CONFIG_FILE))
             print("new user registration.")
+            exit()
         print("Awesome!  Let's start by registering a new user for you.")
-        print("Here's the URL, for reference: http://hub.yt-project.org/ ")
+        print("Here's the URL, for reference: http://hub.yt/ ")
         print()
         print("As always, bail out with Ctrl-C at any time.")
         print()
@@ -586,8 +623,11 @@
         print()
         print("To start out, what's your name?")
         print()
-        name = input("Name? ")
-        if len(name) == 0: sys.exit(1)
+        first_name = input("First Name? ")
+        if len(first_name) == 0: sys.exit(1)
+        print()
+        last_name = input("Last Name? ")
+        if len(last_name) == 0: sys.exit(1)
         print()
         print("And your email address?")
         print()
@@ -604,33 +644,32 @@
             print("Sorry, they didn't match!  Let's try again.")
             print()
         print()
-        print("Would you like a URL displayed for your user?")
-        print("Leave blank if no.")
-        print()
-        url = input("URL? ")
-        print()
         print("Okay, press enter to register.  You should receive a welcome")
         print("message at %s when this is complete." % email)
         print()
         input()
-        data = dict(name = name, email = email, username = username,
-                    password = password1, password2 = password2,
-                    url = url, zap = "rowsdower")
-        data = urllib.parse.urlencode(data)
-        hub_url = "https://hub.yt-project.org/create_user"
-        req = urllib.request.Request(hub_url, data)
-        try:
-            urllib.request.urlopen(req).read()
-        except urllib.error.HTTPError as exc:
-            if exc.code == 400:
-                print("Sorry, the Hub couldn't create your user.")
-                print("You can't register duplicate users, which is the most")
-                print("common cause of this error.  All values for username,")
-                print("name, and email must be unique in our system.")
-                sys.exit(1)
-        except urllib.URLError as exc:
-            print("Something has gone wrong.  Here's the error message.")
-            raise exc
+
+        data = dict(firstName=first_name, email=email, login=username,
+                    password=password1, lastName=last_name, admin=False)
+        hub_url = ytcfg.get("yt", "hub_url")
+        req = requests.post(hub_url + "/user", data=data)
+      
+        if req.ok:
+            headers = {'Girder-Token': req.json()['authToken']['token']}
+        else:
+            if req.status_code == 400:
+                print("Registration failed with 'Bad request':")
+                print(req.json()["message"])
+            exit(1)
+        print("User registration successful")
+        print("Obtaining API key...")
+        req = requests.post(hub_url + "/api_key", headers=headers,
+                            data={'name': 'ytcmd', 'active': True})
+        apiKey = req.json()["key"]
+
+        print("Storing API key in configuration file")
+        set_config("yt", "hub_api_key", apiKey)
+        
         print()
         print("SUCCESS!")
         print()
@@ -810,40 +849,60 @@
         import yt.utilities.lodgeit as lo
         lo.main( None, download=args.number )
 
+class YTHubStartNotebook(YTCommand):
+    args = (
+        dict(dest="folderId", default=ytcfg.get("yt", "hub_sandbox"),
+             nargs="?", 
+             help="(Optional) Hub folder to mount inside the Notebook"),
+    )
+    description = \
+        """
+        Start the Jupyter Notebook on the yt Hub.
+        """
+    subparser = "hub"
+    name = "start"
+    def __call__(self, args):
+        gc = _get_girder_client()
+
+        # TODO: should happen server-side
+        _id = gc._checkResourcePath(args.folderId)
+
+        resp = gc.post("/notebook/{}".format(_id))
+        try:
+            print("Launched! Please visit this URL:")
+            print("    https://tmpnb.hub.yt" + resp['url'])
+            print()
+        except (KeyError, TypeError):
+            print("Something went wrong. The yt Hub responded with : ")
+            print(resp)
+
 class YTNotebookUploadCmd(YTCommand):
     args = (dict(short="file", type=str),)
     description = \
         """
-        Upload an IPython notebook to hub.yt-project.org.
+        Upload an IPython Notebook to the yt Hub.
         """
 
     name = "upload_notebook"
     def __call__(self, args):
-        filename = args.file
-        if not os.path.isfile(filename):
-            raise IOError(filename)
-        if not filename.endswith(".ipynb"):
-            print("File must be an IPython notebook!")
-            return 1
-        import json
-        try:
-            t = json.loads(open(filename).read())['metadata']['name']
-        except (ValueError, KeyError):
-            print("File does not appear to be an IPython notebook.")
-        if len(t) == 0:
-            t = filename.strip(".ipynb")
-        from yt.utilities.minimal_representation import MinimalNotebook
-        mn = MinimalNotebook(filename, t)
-        rv = mn.upload()
+        gc = _get_girder_client()
+        username = gc.get("/user/me")["login"]
+        gc.upload(args.file, "/user/{}/Public".format(username))
+
+        _id = gc.resourceLookup(
+            "/user/{}/Public/{}".format(username, args.file))["_id"]
+        _fid = next(gc.listFile(_id))["_id"]
+        hub_url = urlparse(ytcfg.get("yt", "hub_url"))
         print("Upload successful!")
         print()
         print("To access your raw notebook go here:")
         print()
-        print("  %s" % (rv['url']))
+        print("  {}://{}/#item/{}".format(hub_url.scheme, hub_url.netloc, _id))
         print()
         print("To view your notebook go here:")
         print()
-        print("  %s" % (rv['url'].replace("/go/", "/nb/")))
+        print("  http://nbviewer.jupyter.org/urls/{}/file/{}/download".format(
+            hub_url.netloc + hub_url.path, _fid))
         print()
 
 class YTPlotCmd(YTCommand):
@@ -947,7 +1006,7 @@
             )
     description = \
         """
-        Run the IPython Notebook
+        Start the Jupyter Notebook locally. 
         """
     def __call__(self, args):
         kwargs = {}
@@ -1141,6 +1200,61 @@
             print()
             pprint.pprint(rv)
 
+
+class YTConfigGetCmd(YTCommand):
+    subparser = 'config'
+    name = 'get'
+    description = 'get a config value'
+    args = (dict(short='section', help='The section containing the option.'),
+            dict(short='option', help='The option to retrieve.'))
+    def __call__(self, args):
+        from yt.utilities.configure import get_config
+        print(get_config(args.section, args.option))
+
+
+class YTConfigSetCmd(YTCommand):
+    subparser = 'config'
+    name = 'set'
+    description = 'set a config value'
+    args = (dict(short='section', help='The section containing the option.'),
+            dict(short='option', help='The option to set.'),
+            dict(short='value', help='The value to set the option to.'))
+    def __call__(self, args):
+        from yt.utilities.configure import set_config
+        set_config(args.section, args.option, args.value)
+
+
+class YTConfigRemoveCmd(YTCommand):
+    subparser = 'config'
+    name = 'rm'
+    description = 'remove a config option'
+    args = (dict(short='section', help='The section containing the option.'),
+            dict(short='option', help='The option to remove.'))
+    def __call__(self, args):
+        from yt.utilities.configure import rm_config
+        rm_config(args.section, args.option)
+
+
+class YTConfigListCmd(YTCommand):
+    subparser = 'config'
+    name = 'list'
+    description = 'show the config content'
+    args = ()
+    def __call__(self, args):
+        from yt.utilities.configure import write_config
+        write_config(sys.stdout)
+
+
+class YTConfigMigrateCmd(YTCommand):
+    subparser = 'config'
+    name = 'migrate'
+    description = 'migrate old config file'
+    args = ()
+    def __call__(self, args):
+        from yt.utilities.configure import migrate_config
+        migrate_config()
+
+
 class YTSearchCmd(YTCommand):
     args = (dict(short="-o", longname="--output",
                  action="store", type=str,

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 yt/utilities/configure.py
--- /dev/null
+++ b/yt/utilities/configure.py
@@ -0,0 +1,92 @@
+# -*- coding: UTF-8 -*-
+#-----------------------------------------------------------------------------
+# Copyright (c) 2016, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+import os
+import sys
+import argparse
+from yt.config import CURRENT_CONFIG_FILE, _OLD_CONFIG_FILE
+from yt.extern.six.moves import configparser
+
+CONFIG = configparser.SafeConfigParser()
+CONFIG.read([CURRENT_CONFIG_FILE])
+
+
+def get_config(section, option):
+    return CONFIG.get(section, option)
+
+
+def set_config(section, option, value):
+    if not CONFIG.has_section(section):
+        CONFIG.add_section(section)
+    CONFIG.set(section, option, value)
+    write_config()
+
+
+def write_config(fd=None):
+    if fd is None:
+        with open(CURRENT_CONFIG_FILE, 'w') as fd:
+            CONFIG.write(fd)
+    else:
+        CONFIG.write(fd)
+
+def migrate_config():
+    if not os.path.exists(_OLD_CONFIG_FILE):
+        print("Old config not found.")
+        sys.exit()
+    CONFIG.read(_OLD_CONFIG_FILE)
+    print("Writing a new config file to: {}".format(CURRENT_CONFIG_FILE))
+    write_config()
+    print("Backing up the old config file: {}.bak".format(_OLD_CONFIG_FILE))
+    os.rename(_OLD_CONFIG_FILE, _OLD_CONFIG_FILE + '.bak')
+
+
+def rm_config(section, option):
+    CONFIG.remove_option(section, option)
+    write_config()
+
+
+def main():
+    parser = argparse.ArgumentParser(
+        description='Get and set configuration values for yt')
+    subparsers = parser.add_subparsers(help='sub-command help', dest='cmd')
+
+    get_parser = subparsers.add_parser('get', help='get a config value')
+    set_parser = subparsers.add_parser('set', help='set a config value')
+    rm_parser = subparsers.add_parser('rm', help='remove a config option')
+    subparsers.add_parser('migrate', help='migrate old config file')
+    subparsers.add_parser('list', help='show all config values')
+
+    get_parser.add_argument(
+        'section', help='The section containing the option.')
+    get_parser.add_argument('option', help='The option to retrieve.')
+
+    set_parser.add_argument(
+        'section', help='The section containing the option.')
+    set_parser.add_argument('option', help='The option to set.')
+    set_parser.add_argument('value', help='The value to set the option to.')
+
+    rm_parser.add_argument(
+        'section', help='The section containing the option to remove.')
+    rm_parser.add_argument('option', help='The option to remove.')
+
+    args = parser.parse_args()
+
+    if args.cmd == 'get':
+        print(get_config(args.section, args.option))
+    elif args.cmd == 'set':
+        set_config(args.section, args.option, args.value)
+    elif args.cmd == 'list':
+        write_config(sys.stdout)
+    elif args.cmd == 'migrate':
+        migrate_config()
+    elif args.cmd == 'rm':
+        rm_config(args.section, args.option)
+
+if __name__ == '__main__':
+    main()  # pragma: no cover

diff -r b1165fbb7bd24dcdbf61093a685f540567a7de87 -r 42d65f24f2d8f10b60704b33038c976cdcf0c580 yt/utilities/tests/test_config.py
--- /dev/null
+++ b/yt/utilities/tests/test_config.py
@@ -0,0 +1,142 @@
+# -*- coding: UTF-8 -*-
+#-----------------------------------------------------------------------------
+# Copyright (c) 2016, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+import contextlib
+import mock
+import os
+import sys
+import unittest
+import yt.utilities.command_line
+import yt.config
+from yt.config import \
+    CURRENT_CONFIG_FILE, _OLD_CONFIG_FILE
+from yt.extern.six import StringIO
+from yt.extern.six.moves.configparser import NoOptionError, SafeConfigParser
+
+
+_DUMMY_CFG = ['[yt]', 'loglevel = 49']
+
+
+ at contextlib.contextmanager
+def captureOutput():
+    oldout, olderr = sys.stdout, sys.stderr
+    try:
+        out = [StringIO(), StringIO()]
+        sys.stdout, sys.stderr = out
+        yield out
+    finally:
+        sys.stdout, sys.stderr = oldout, olderr
+        out[0] = out[0].getvalue()
+        out[1] = out[1].getvalue()
+
+
+class SysExitException(Exception):
+    pass
+
+
+def setUpModule():
+    for cfgfile in (CURRENT_CONFIG_FILE, _OLD_CONFIG_FILE):
+        if os.path.exists(cfgfile):
+            os.rename(cfgfile, cfgfile + '.bak_test')
+
+            if cfgfile == CURRENT_CONFIG_FILE:
+                yt.utilities.configure.CONFIG = SafeConfigParser()
+                if not yt.utilities.configure.CONFIG.has_section('yt'):
+                    yt.utilities.configure.CONFIG.add_section('yt')
+
+
+def tearDownModule():
+    for cfgfile in (CURRENT_CONFIG_FILE, _OLD_CONFIG_FILE): 
+        if os.path.exists(cfgfile + '.bak_test'):
+            os.rename(cfgfile + '.bak_test', cfgfile)
+
+
+class TestYTConfig(unittest.TestCase):
+    def _runYTConfig(self, args):
+        args = ['yt', 'config'] + args
+        retcode = 0
+
+        with mock.patch.object(sys, 'argv', args),\
+                mock.patch('sys.exit', side_effect=SysExitException) as exit,\
+                captureOutput() as output:
+            try:
+                yt.utilities.command_line.run_main()
+            except SysExitException:
+                args = exit.mock_calls[0][1]
+                retcode = args[0] if len(args) else 0
+        return {
+            'rc': retcode,
+            'stdout': output[0],
+            'stderr': output[1]
+        }
+
+class TestYTConfigCommands(TestYTConfig):
+    def testConfigCommands(self):
+        self.assertFalse(os.path.exists(CURRENT_CONFIG_FILE))
+
+        info = self._runYTConfig(['--help'])
+        self.assertEqual(info['rc'], 0)
+        self.assertEqual(info['stderr'], '')
+        self.assertIn('Get and set configuration values for yt',
+                      info['stdout'])
+
+        info = self._runYTConfig(['list'])
+        self.assertEqual(info['rc'], 0)
+        self.assertIn('[yt]', info['stdout'])
+
+        info = self._runYTConfig(['set', 'yt', '__parallel', 'True'])
+        self.assertEqual(info['rc'], 0)
+
+        info = self._runYTConfig(['get', 'yt', '__parallel'])
+        self.assertEqual(info['rc'], 0)
+        self.assertEqual(info['stdout'].strip(), 'True')
+
+        info = self._runYTConfig(['rm', 'yt', '__parallel'])
+        self.assertEqual(info['rc'], 0)
+
+        with self.assertRaises(NoOptionError):
+            self._runYTConfig(['get', 'yt', 'foo'])
+    
+    def tearDown(self):
+        if os.path.exists(CURRENT_CONFIG_FILE):
+            os.remove(CURRENT_CONFIG_FILE)
+
+class TestYTConfigMigration(TestYTConfig):
+
+    def setUp(self):
+        if not os.path.exists(os.path.dirname(_OLD_CONFIG_FILE)):
+            os.makedirs(os.path.dirname(_OLD_CONFIG_FILE))
+
+        with open(_OLD_CONFIG_FILE, 'w') as fh:
+            for line in _DUMMY_CFG:
+                fh.write('{}\n'.format(line))
+        
+        if os.path.exists(CURRENT_CONFIG_FILE):
+            os.remove(CURRENT_CONFIG_FILE)
+
+    def tearDown(self):
+        if os.path.exists(CURRENT_CONFIG_FILE):
+            os.remove(CURRENT_CONFIG_FILE)
+        if os.path.exists(_OLD_CONFIG_FILE + '.bak'):
+            os.remove(_OLD_CONFIG_FILE + '.bak')
+
+    def testConfigMigration(self):
+        self.assertFalse(os.path.exists(CURRENT_CONFIG_FILE))
+        self.assertTrue(os.path.exists(_OLD_CONFIG_FILE))
+        
+        info = self._runYTConfig(['migrate'])
+        self.assertEqual(info['rc'], 0)
+
+        self.assertTrue(os.path.exists(CURRENT_CONFIG_FILE))
+        self.assertFalse(os.path.exists(_OLD_CONFIG_FILE))
+        self.assertTrue(os.path.exists(_OLD_CONFIG_FILE + '.bak'))
+
+        with open(CURRENT_CONFIG_FILE, 'r') as fh:
+            new_cfg = ''.join(fh.readlines())
+        self.assertEqual(new_cfg.strip().split('\n'), _DUMMY_CFG)

Repository URL: https://bitbucket.org/yt_analysis/yt/

--

This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.



More information about the yt-svn mailing list