Repository: Ouranosinc/xclim
Pull request #15 (2018-09-04 20:29:33)

with_attrs now assigns attributes to the output DataArray. 


Patch:
diff --git a/docs/conf.py b/docs/conf.py
index c2eed7fd..b15683b5 100755
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -13,20 +13,16 @@
 # All configuration values have a default; values that are commented out
 # serve to show the default.
 
-import os
-import sys
-
 # If extensions (or modules to document with autodoc) are in another
 # directory, add these directories to sys.path here. If the directory is
 # relative to the documentation root, use os.path.abspath to make it
 # absolute, like shown here.
 #
-import guzzle_sphinx_theme
+import os
+import sys
+sys.path.insert(0, os.path.abspath('..'))
 
 import xclim
-from xclim import __version__
-
-sys.path.insert(0, os.path.abspath('..'))
 
 # -- General configuration ---------------------------------------------
 
@@ -36,14 +32,10 @@ sys.path.insert(0, os.path.abspath('..'))
 
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = [
-    'sphinx.ext.autodoc',
-    'sphinx.ext.viewcode',
-    'sphinx.ext.mathjax',
-    'sphinx.ext.napoleon'
-]
-
-extensions.append("guzzle_sphinx_theme")
+extensions = ['sphinx.ext.autodoc',
+              'sphinx.ext.viewcode',
+              'sphinx.ext.mathjax',
+              'sphinx.ext.napoleon']
 
 napoleon_numpy_docstring = True
 napoleon_use_rtype = False
@@ -90,45 +82,34 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
 pygments_style = 'sphinx'
 
 # If true, `todo` and `todoList` produce output, else they produce nothing.
-todo_include_todos = True
+todo_include_todos = False
+
 
 # -- Options for HTML output -------------------------------------------
 
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
 #
-html_title = "XClim Official Documentation"
-html_short_title = "XClim"
-
-html_theme_path = guzzle_sphinx_theme.html_theme_path()
-html_theme = 'guzzle_sphinx_theme'  # 'alabaster
+html_theme = 'alabaster'
 
 # Theme options are theme-specific and customize the look and feel of a
 # theme further.  For a list of options available for each theme, see the
 # documentation.
 #
-html_theme_options = {
-    "project_nav_name": "XClim {}".format(__version__),
-    "homepage": "index"
-}
-
-html_sidebars = {
-    '**': ['logo-text.html',
-           'globaltoc.html',
-           'localtoc.html',
-           'searchbox.html']
-}
+# html_theme_options = {}
 
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
 html_static_path = ['_static']
 
+
 # -- Options for HTMLHelp output ---------------------------------------
 
 # Output file base name for HTML help builder.
 htmlhelp_basename = 'xclimdoc'
 
+
 # -- Options for LaTeX output ------------------------------------------
 
 latex_elements = {
@@ -158,6 +139,7 @@ latex_documents = [
      u'Travis Logan', 'manual'),
 ]
 
+
 # -- Options for manual page output ------------------------------------
 
 # One entry per manual page. List of tuples
@@ -168,6 +150,7 @@ man_pages = [
      [author], 1)
 ]
 
+
 # -- Options for Texinfo output ----------------------------------------
 
 # Grouping the document tree into Texinfo files. List of tuples
@@ -181,3 +164,6 @@ texinfo_documents = [
      'One line description of project.',
      'Miscellaneous'),
 ]
+
+
+
diff --git a/docs/index.rst b/docs/index.rst
index 12c1e2c0..a713c6c8 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,5 +1,5 @@
-xclim Official Documentation
-============================
+Welcome to xclim's documentation!
+=====================================
 
 .. toctree::
    :maxdepth: 2
diff --git a/requirements.txt b/requirements.txt
index 93528a73..0e8a061d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,4 +4,3 @@ numpy
 scipy
 bottleneck
 netCDF4
-guzzle-sphinx-theme
diff --git a/setup.py b/setup.py
index e11e2e59..8d6cb367 100644
--- a/setup.py
+++ b/setup.py
@@ -14,7 +14,7 @@ with open('HISTORY.rst') as history_file:
 #with open('requirements.txt') as req_file:
 #    requirements = req_file.read().split('\n')
 
-requirements = ['dask', 'numpy', 'scipy', 'xarray', 'netcdf4', 'guzzle_sphinx_theme']
+requirements = ['dask', 'numpy', 'scipy', 'xarray', 'netcdf4']
 
 setup_requirements = ['pytest-runner', ]
 
diff --git a/xclim/indices.py b/xclim/indices.py
index fd5e6681..607011e4 100644
--- a/xclim/indices.py
+++ b/xclim/indices.py
@@ -24,28 +24,28 @@ def first_paragraph(txt):
 
 
 def with_attrs(**func_attrs):
-    """Set attributes in the decorated function, at definition time.
-    Only accepts keyword arguments.
-
-    E.g.:
-        @with_attrs(counter=0, something='boing')
-        def count_it():
-            count_it.counter += 1
-        print count_it.counter
-        print count_it.something
-        # Out:
-        # >>> 0
-        # >>> 'boing'
+    """Set attributes in the decorated function at definition time,
+    and assign these attributes to the function output at the
+    execution time.
+
+    Notes
+    -----
+    Assumes the output has an attrs dictionary attribute (e.g. xarray.DataArray).
     """
     def attr_decorator(fn):
+        # Use the docstring as the description attribute.
+        func_attrs['description'] = first_paragraph(fn.__doc__)
+
         @wraps(fn)
         def wrapper(*args, **kwargs):
-            return fn(*args, **kwargs)
+            out = fn(*args, **kwargs)
+            out.attrs.update(func_attrs)
+            return out
 
+        # Assign the attributes to the function itself
         for attr, value in func_attrs.items():
             setattr(wrapper, attr, value)
 
-        setattr(wrapper, 'description', first_paragraph(fn.__doc__))
         return wrapper
 
     return attr_decorator


Test patch:
diff --git a/tests/test_indices.py b/tests/test_indices.py
index 70547f7c..7edda8f7 100644
--- a/tests/test_indices.py
+++ b/tests/test_indices.py
@@ -71,6 +71,14 @@ class Test_cooling_degree_days():
         cdd = cooling_degree_days(a)
         assert cdd == 10
 
+    def test_attrs(self):
+        a = self.time_series(np.array([20, 25, -15, 19]) + K2C)
+        cdd = cooling_degree_days(a)
+        assert cdd.standard_name == 'cooling_degree_days'
+        assert cdd.long_name == 'cooling degree days'
+        assert cdd.units == 'K*day'
+        assert len(cdd.description) > 0
+
 # I'd like to parametrize some of these tests so we don't have to write individual tests for each indicator.
 @pytest.mark.skip('')
 class TestTG():